fix: align market selection checkboxes with rows
- Fix checkbox column misalignment with creator list items - Add syncContentCellHeight to keep selection cells aligned with native rows - Add MarketAlignmentDiagnostic for debugging alignment issues - Update documentation to clarify dist-release folder usage - Add npm run build:release step to colleague setup guide
This commit is contained in:
parent
ecfe136628
commit
02be56888a
@ -43,6 +43,8 @@ git clone https://git.internal.intelligrow.cn/wangshaoqing/star-chart-search-enh
|
|||||||
star-chart-search-enhancer/dist-release/
|
star-chart-search-enhancer/dist-release/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
⚠️ **重要**:必须选择 `dist-release` 这个子文件夹,不要选外层文件夹
|
||||||
|
|
||||||
✅ 安装成功!你会看到插件卡片。
|
✅ 安装成功!你会看到插件卡片。
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -74,10 +76,16 @@ git clone https://git.internal.intelligrow.cn/wangshaoqing/star-chart-search-enh
|
|||||||
```bash
|
```bash
|
||||||
cd Desktop/star-chart-search-enhancer
|
cd Desktop/star-chart-search-enhancer
|
||||||
git pull
|
git pull
|
||||||
|
npm run build:release
|
||||||
```
|
```
|
||||||
|
|
||||||
然后到 `chrome://extensions` 页面点击插件卡片的 **"重新加载"** 🔄
|
然后到 `chrome://extensions` 页面点击插件卡片的 **"重新加载"** 🔄
|
||||||
|
|
||||||
|
⚠️ **如果重新加载后还是旧版本**:
|
||||||
|
- 先点击插件卡片的 **"移除"** 删除旧版本
|
||||||
|
- 然后重新点击 **"加载已解压的扩展程序"**
|
||||||
|
- 再次选择 `dist-release` 文件夹
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ❓ 常见问题
|
## ❓ 常见问题
|
||||||
|
|||||||
@ -37,7 +37,9 @@
|
|||||||
|
|
||||||
4. 点击左上角出现的 **"加载已解压的扩展程序"**
|
4. 点击左上角出现的 **"加载已解压的扩展程序"**
|
||||||
|
|
||||||
5. 选择刚才解压出来的那个文件夹
|
5. 选择刚才解压出来的文件夹里的 **`dist-release`** 文件夹
|
||||||
|
|
||||||
|
⚠️ **重要**:必须选择 `dist-release` 这个子文件夹,不要选外层文件夹
|
||||||
|
|
||||||
6. 看到绿色的插件卡片出现,就装好了!
|
6. 看到绿色的插件卡片出现,就装好了!
|
||||||
|
|
||||||
@ -95,6 +97,11 @@ https://xingtu.cn/ad/creator/market
|
|||||||
3. 打开 `chrome://extensions`
|
3. 打开 `chrome://extensions`
|
||||||
4. 找到插件卡片,点击 **"重新加载"** 🔄
|
4. 找到插件卡片,点击 **"重新加载"** 🔄
|
||||||
|
|
||||||
|
⚠️ **如果重新加载后还是旧版本**:
|
||||||
|
- 先点击插件卡片的 **"移除"** 删除旧版本
|
||||||
|
- 然后重新点击 **"加载已解压的扩展程序"**
|
||||||
|
- 再次选择 `dist-release` 文件夹
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ❓ 常见问题
|
## ❓ 常见问题
|
||||||
|
|||||||
64
package-lock.json
generated
64
package-lock.json
generated
@ -12,6 +12,7 @@
|
|||||||
"@logto/chrome-extension": "^0.1.27"
|
"@logto/chrome-extension": "^0.1.27"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.59.1",
|
||||||
"jsdom": "^29.0.2",
|
"jsdom": "^29.0.2",
|
||||||
"tsup": "^8.5.1",
|
"tsup": "^8.5.1",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
@ -826,6 +827,22 @@
|
|||||||
"url": "https://github.com/sponsors/Boshen"
|
"url": "https://github.com/sponsors/Boshen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@playwright/test": {
|
||||||
|
"version": "1.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz",
|
||||||
|
"integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright": "1.59.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.0.0-rc.16",
|
"version": "1.0.0-rc.16",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz",
|
||||||
@ -2502,6 +2519,53 @@
|
|||||||
"pathe": "^2.0.1"
|
"pathe": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/playwright": {
|
||||||
|
"version": "1.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
|
||||||
|
"integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"playwright-core": "1.59.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"playwright": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright-core": {
|
||||||
|
"version": "1.59.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
|
||||||
|
"integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"playwright-core": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/playwright/node_modules/fsevents": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.10",
|
"version": "8.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
},
|
},
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.59.1",
|
||||||
"jsdom": "^29.0.2",
|
"jsdom": "^29.0.2",
|
||||||
"tsup": "^8.5.1",
|
"tsup": "^8.5.1",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
|
|||||||
@ -99,10 +99,39 @@ export interface MarketTableDom {
|
|||||||
rows: MarketRowDom[];
|
rows: MarketRowDom[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MarketAlignmentDiagnostic {
|
||||||
|
authorId: string;
|
||||||
|
authorName: string;
|
||||||
|
checkboxTop: number;
|
||||||
|
rowTop: number;
|
||||||
|
topDelta: number;
|
||||||
|
}
|
||||||
|
|
||||||
export function syncMarketTable(root: ParentNode): MarketTableDom | null {
|
export function syncMarketTable(root: ParentNode): MarketTableDom | null {
|
||||||
return syncSyntheticMarketTable(root) ?? syncDivGridMarketTable(root);
|
return syncSyntheticMarketTable(root) ?? syncDivGridMarketTable(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readMarketAlignmentDiagnostics(
|
||||||
|
table: MarketTableDom
|
||||||
|
): MarketAlignmentDiagnostic[] {
|
||||||
|
return table.rows.map((rowDom) => {
|
||||||
|
const selectionCell = rowDom.selectionCheckbox.parentElement;
|
||||||
|
const selectionRect = selectionCell?.getBoundingClientRect();
|
||||||
|
const rowRect = rowDom.row.getBoundingClientRect();
|
||||||
|
|
||||||
|
const checkboxTop = selectionRect?.top ?? Number.NaN;
|
||||||
|
const rowTop = rowRect.top ?? Number.NaN;
|
||||||
|
|
||||||
|
return {
|
||||||
|
authorId: rowDom.authorId,
|
||||||
|
authorName: rowDom.authorName,
|
||||||
|
checkboxTop,
|
||||||
|
rowTop,
|
||||||
|
topDelta: checkboxTop - rowTop
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function readMarketPageSignature(root: ParentNode): string {
|
export function readMarketPageSignature(root: ParentNode): string {
|
||||||
const document = getOwnerDocument(root);
|
const document = getOwnerDocument(root);
|
||||||
const explicitPageIndex =
|
const explicitPageIndex =
|
||||||
@ -801,14 +830,15 @@ function syncDivColumnCells(
|
|||||||
const templateCells = getDirectContentCells(templateColumn);
|
const templateCells = getDirectContentCells(templateColumn);
|
||||||
for (let index = 0; index < rowCount; index += 1) {
|
for (let index = 0; index < rowCount; index += 1) {
|
||||||
const existingCell = getDirectContentCells(column)[index] ?? null;
|
const existingCell = getDirectContentCells(column)[index] ?? null;
|
||||||
|
const templateCell =
|
||||||
|
templateCells[index] ?? templateCells[templateCells.length - 1] ?? null;
|
||||||
if (existingCell) {
|
if (existingCell) {
|
||||||
existingCell.dataset.marketRowCell = field;
|
existingCell.dataset.marketRowCell = field;
|
||||||
applyPluginContentCellStyles(existingCell);
|
applyPluginContentCellStyles(existingCell);
|
||||||
|
syncContentCellHeight(existingCell, templateCell);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const templateCell =
|
|
||||||
templateCells[index] ?? templateCells[templateCells.length - 1] ?? null;
|
|
||||||
const nextCell =
|
const nextCell =
|
||||||
field === SELECTION_COLUMN_KEY
|
field === SELECTION_COLUMN_KEY
|
||||||
? templateCell
|
? templateCell
|
||||||
@ -820,11 +850,31 @@ function syncDivColumnCells(
|
|||||||
nextCell.dataset.marketRowCell = field;
|
nextCell.dataset.marketRowCell = field;
|
||||||
applyColumnWidth(nextCell, field);
|
applyColumnWidth(nextCell, field);
|
||||||
applyPluginContentCellStyles(nextCell);
|
applyPluginContentCellStyles(nextCell);
|
||||||
|
syncContentCellHeight(nextCell, templateCell);
|
||||||
nextCell.textContent = "";
|
nextCell.textContent = "";
|
||||||
column.appendChild(nextCell);
|
column.appendChild(nextCell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncContentCellHeight(
|
||||||
|
cell: HTMLElement,
|
||||||
|
templateCell: HTMLElement | null
|
||||||
|
): void {
|
||||||
|
if (!templateCell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const measuredHeight = Math.round(templateCell.getBoundingClientRect().height);
|
||||||
|
const nextHeight =
|
||||||
|
measuredHeight > 0 ? `${measuredHeight}px` : templateCell.style.height;
|
||||||
|
|
||||||
|
if (nextHeight) {
|
||||||
|
cell.style.height = nextHeight;
|
||||||
|
} else {
|
||||||
|
cell.style.removeProperty("height");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function applyPluginHeaderCellStyles(cell: HTMLElement): void {
|
function applyPluginHeaderCellStyles(cell: HTMLElement): void {
|
||||||
cell.style.display = "flex";
|
cell.style.display = "flex";
|
||||||
cell.style.alignItems = "center";
|
cell.style.alignItems = "center";
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { createBatchPayload, type BatchPayload } from "./batch-payload";
|
|||||||
import {
|
import {
|
||||||
applyRowOrder,
|
applyRowOrder,
|
||||||
applyRowVisibility,
|
applyRowVisibility,
|
||||||
|
readMarketAlignmentDiagnostics,
|
||||||
readMarketPageSignature,
|
readMarketPageSignature,
|
||||||
renderMarketRowState,
|
renderMarketRowState,
|
||||||
syncPluginSortHeaders,
|
syncPluginSortHeaders,
|
||||||
@ -396,6 +397,7 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
applyRowOrder(table, records.map((record) => record.authorId));
|
applyRowOrder(table, records.map((record) => record.authorId));
|
||||||
bindSelectionControls(table);
|
bindSelectionControls(table);
|
||||||
syncMarketSelectionState(table, selectedAuthorIds);
|
syncMarketSelectionState(table, selectedAuthorIds);
|
||||||
|
logMarketAlignmentDiagnosticsIfEnabled(options.window, table, "applyCurrentView");
|
||||||
lastKnownPageSignature = readMarketPageSignature(options.document);
|
lastKnownPageSignature = readMarketPageSignature(options.document);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -662,12 +664,23 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const step = Math.max(scrollContainer.clientHeight, 240);
|
const step = Math.max(scrollContainer.clientHeight, 240);
|
||||||
|
logMarketScrollTraceIfEnabled(options.window, {
|
||||||
|
event: "start",
|
||||||
|
maxScrollTop,
|
||||||
|
originalScrollTop,
|
||||||
|
step
|
||||||
|
});
|
||||||
for (
|
for (
|
||||||
let nextScrollTop = Math.min(originalScrollTop + step, maxScrollTop);
|
let nextScrollTop = Math.min(originalScrollTop + step, maxScrollTop);
|
||||||
nextScrollTop > originalScrollTop && nextScrollTop <= maxScrollTop;
|
nextScrollTop > originalScrollTop && nextScrollTop <= maxScrollTop;
|
||||||
nextScrollTop = Math.min(nextScrollTop + step, maxScrollTop)
|
nextScrollTop = Math.min(nextScrollTop + step, maxScrollTop)
|
||||||
) {
|
) {
|
||||||
setScrollTop(scrollContainer, nextScrollTop);
|
setScrollTop(scrollContainer, nextScrollTop);
|
||||||
|
logMarketScrollTraceIfEnabled(options.window, {
|
||||||
|
event: "step",
|
||||||
|
nextScrollTop,
|
||||||
|
scrollTop: scrollContainer.scrollTop
|
||||||
|
});
|
||||||
hydrationSnapshot = await collectCurrentPageSnapshotsUntilSettled();
|
hydrationSnapshot = await collectCurrentPageSnapshotsUntilSettled();
|
||||||
if (
|
if (
|
||||||
hydrationSnapshot.missingDefaultFieldCount === 0 &&
|
hydrationSnapshot.missingDefaultFieldCount === 0 &&
|
||||||
@ -683,6 +696,10 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
|||||||
|
|
||||||
if (scrollContainer.scrollTop !== originalScrollTop) {
|
if (scrollContainer.scrollTop !== originalScrollTop) {
|
||||||
setScrollTop(scrollContainer, originalScrollTop);
|
setScrollTop(scrollContainer, originalScrollTop);
|
||||||
|
logMarketScrollTraceIfEnabled(options.window, {
|
||||||
|
event: "restore",
|
||||||
|
restoredScrollTop: scrollContainer.scrollTop
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,6 +1026,45 @@ function setScrollTop(element: HTMLElement, top: number): void {
|
|||||||
element.dispatchEvent(new Event("scroll"));
|
element.dispatchEvent(new Event("scroll"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logMarketAlignmentDiagnosticsIfEnabled(
|
||||||
|
window: Window,
|
||||||
|
table: ReturnType<typeof syncMarketTable>,
|
||||||
|
label: string
|
||||||
|
): void {
|
||||||
|
if (!isMarketDebugLoggingEnabled(window) || !table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const diagnostics = readMarketAlignmentDiagnostics(table);
|
||||||
|
console.info(`[SCES debug] ${label} alignment`, diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logMarketScrollTraceIfEnabled(
|
||||||
|
window: Window,
|
||||||
|
payload: Record<string, unknown>
|
||||||
|
): void {
|
||||||
|
if (!isMarketDebugLoggingEnabled(window)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info("[SCES debug] submit/export scroll", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMarketDebugLoggingEnabled(window: Window): boolean {
|
||||||
|
try {
|
||||||
|
const searchParams = new URL(window.location.href).searchParams;
|
||||||
|
if (searchParams.get("scesDebug") === "1") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return window.localStorage.getItem("scesDebugMarket") === "1";
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function readCurrentPageRows(document: Document): MarketRowSnapshot[] {
|
function readCurrentPageRows(document: Document): MarketRowSnapshot[] {
|
||||||
const table = syncMarketTable(document);
|
const table = syncMarketTable(document);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
applyRowVisibility,
|
applyRowVisibility,
|
||||||
findNextPageControl,
|
findNextPageControl,
|
||||||
isPageControlDisabled,
|
isPageControlDisabled,
|
||||||
|
readMarketAlignmentDiagnostics,
|
||||||
readMarketPageSignature,
|
readMarketPageSignature,
|
||||||
renderMarketRowState,
|
renderMarketRowState,
|
||||||
syncMarketTable
|
syncMarketTable
|
||||||
@ -329,6 +330,70 @@ describe("market-dom-sync", () => {
|
|||||||
expect(readSelectionCellHeights()).toEqual(["120px", "120px"]);
|
expect(readSelectionCellHeights()).toEqual(["120px", "120px"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("resyncs selection cell heights when native author row heights change", () => {
|
||||||
|
document.body.innerHTML = buildRealMarketGridFixture();
|
||||||
|
|
||||||
|
expect(syncMarketTable(document)).not.toBeNull();
|
||||||
|
expect(readSelectionCellHeights()).toEqual(["120px", "120px"]);
|
||||||
|
|
||||||
|
const authorCells = Array.from(
|
||||||
|
document.querySelectorAll('[data-testid="author-section"] .content-column:not([data-market-column-group="selection"]) > .content-cell')
|
||||||
|
) as HTMLElement[];
|
||||||
|
const middleCells = Array.from(
|
||||||
|
document.querySelectorAll('.middle-columns .content-column > .content-cell')
|
||||||
|
) as HTMLElement[];
|
||||||
|
const rightCells = Array.from(
|
||||||
|
document.querySelectorAll('[data-testid="right-section"] .content-column > .content-cell')
|
||||||
|
) as HTMLElement[];
|
||||||
|
|
||||||
|
[...authorCells, ...middleCells, ...rightCells].forEach((cell) => {
|
||||||
|
cell.style.height = "152px";
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(syncMarketTable(document)).not.toBeNull();
|
||||||
|
expect(readSelectionCellHeights()).toEqual(["152px", "152px"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reads alignment diagnostics for selection cells against native rows", () => {
|
||||||
|
document.body.innerHTML = buildRealMarketGridFixture();
|
||||||
|
|
||||||
|
const table = syncMarketTable(document);
|
||||||
|
if (!table) {
|
||||||
|
throw new Error("Expected market table");
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstSelectionCell = table.rows[0].selectionCheckbox.parentElement as HTMLElement;
|
||||||
|
const secondSelectionCell = table.rows[1].selectionCheckbox.parentElement as HTMLElement;
|
||||||
|
|
||||||
|
vi.spyOn(firstSelectionCell, "getBoundingClientRect").mockReturnValue(
|
||||||
|
createRect({ height: 24, top: 100 })
|
||||||
|
);
|
||||||
|
vi.spyOn(table.rows[0].row, "getBoundingClientRect").mockReturnValue(
|
||||||
|
createRect({ height: 120, top: 120 })
|
||||||
|
);
|
||||||
|
vi.spyOn(secondSelectionCell, "getBoundingClientRect").mockReturnValue(
|
||||||
|
createRect({ height: 24, top: 260 })
|
||||||
|
);
|
||||||
|
vi.spyOn(table.rows[1].row, "getBoundingClientRect").mockReturnValue(
|
||||||
|
createRect({ height: 120, top: 250 })
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(readMarketAlignmentDiagnostics(table)).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
authorId: "111",
|
||||||
|
checkboxTop: 100,
|
||||||
|
rowTop: 120,
|
||||||
|
topDelta: -20
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
authorId: "222",
|
||||||
|
checkboxTop: 260,
|
||||||
|
rowTop: 250,
|
||||||
|
topDelta: 10
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test("uses native-like alignment styles for plugin cells", () => {
|
test("uses native-like alignment styles for plugin cells", () => {
|
||||||
document.body.innerHTML = buildRealMarketGridFixtureWithScopedAttributes();
|
document.body.innerHTML = buildRealMarketGridFixtureWithScopedAttributes();
|
||||||
|
|
||||||
@ -1047,3 +1112,25 @@ function readVisualCells(root: Element | null): HTMLElement[] {
|
|||||||
return cells.indexOf(left) - cells.indexOf(right);
|
return cells.indexOf(left) - cells.indexOf(right);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createRect({
|
||||||
|
height,
|
||||||
|
top
|
||||||
|
}: {
|
||||||
|
height: number;
|
||||||
|
top: number;
|
||||||
|
}): DOMRect {
|
||||||
|
return {
|
||||||
|
bottom: top + height,
|
||||||
|
height,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
toJSON() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
top,
|
||||||
|
width: 0,
|
||||||
|
x: 0,
|
||||||
|
y: top
|
||||||
|
} as DOMRect;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user