Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/trees/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
"test": "bun test",
"coverage": "bun test --coverage",
"test:e2e": "bun run build && (bun ./test/e2e/check-playwright-binary.ts || bun run test:e2e:installbinary) && bunx playwright test -c test/e2e/playwright.config.ts",
"test:e2e:docs-anchor": "bun run build && (bun ./test/e2e/check-playwright-binary.ts || bun run test:e2e:installbinary) && PATH_STORE_DOCS_E2E=1 bunx playwright test -c test/e2e/playwright.config.ts test/e2e/path-store-docs-anchor.pw.ts --reporter=line",
"test:e2e:installbinary": "bunx playwright@1.51.1 install chromium",
"test:e2e:server": "vite --config test/e2e/vite.config.ts",
"tsc": "tsgo --noEmit --pretty",
Expand Down
82 changes: 7 additions & 75 deletions packages/trees/src/path-store/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,6 @@ const BLOCKED_CONTEXT_MENU_NAV_KEYS = new Set([
'PageUp',
]);

const CONTEXT_MENU_ROW_ANCHOR_NAME = '--path-store-context-row';
let cachedAnchorSupportCss: typeof CSS | null | undefined;
let cachedAnchorSupportValue: boolean | null = null;

function isEventInContextMenu(event: Event): boolean {
for (const entry of event.composedPath()) {
if (!(entry instanceof HTMLElement)) {
Expand Down Expand Up @@ -254,25 +250,6 @@ function getContextMenuAnchorTop(
return itemRect.top - scrollRect.top + scrollElement.scrollTop;
}

function supportsContextMenuAnchorPositioning(): boolean {
const currentCss = typeof CSS === 'undefined' ? null : CSS;
if (
cachedAnchorSupportCss === currentCss &&
cachedAnchorSupportValue != null
) {
return cachedAnchorSupportValue;
}

cachedAnchorSupportCss = currentCss;
cachedAnchorSupportValue =
currentCss != null &&
currentCss.supports('anchor-name', CONTEXT_MENU_ROW_ANCHOR_NAME) &&
currentCss.supports('position-anchor', CONTEXT_MENU_ROW_ANCHOR_NAME) &&
currentCss.supports('top', 'anchor(top)');

return cachedAnchorSupportValue;
}

function createContextMenuItem(
row: PathStoreTreesVisibleRow,
path: string
Expand Down Expand Up @@ -329,8 +306,6 @@ function renderStyledRow(
controller: PathStoreTreesController,
row: PathStoreTreesVisibleRow,
visualFocusPath: string | null,
contextAnchorName: string | null,
contextAnchorPath: string | null,
contextHoverPath: string | null,
itemHeight: number,
contextMenuEnabled: boolean,
Expand Down Expand Up @@ -361,14 +336,6 @@ function renderStyledRow(
? { 'data-item-focused': true }
: {};
const selectedProps = row.isSelected ? { 'data-item-selected': true } : {};
const contextAnchorProps =
contextAnchorPath === targetPath
? { 'data-item-context-anchor': 'true' }
: {};
const contextAnchorStyle =
contextAnchorPath === targetPath && contextAnchorName != null
? { anchorName: contextAnchorName }
: undefined;
const contextHoverProps =
contextHoverPath === targetPath
? { 'data-item-context-hover': 'true' }
Expand Down Expand Up @@ -424,14 +391,9 @@ function renderStyledRow(
onKeyDown={onKeyDown}
role="treeitem"
tabIndex={row.isFocused ? 0 : -1}
style={{
minHeight: `${itemHeight}px`,
...contextAnchorStyle,
...style,
}}
style={{ minHeight: `${itemHeight}px`, ...style }}
{...focusedProps}
{...selectedProps}
{...contextAnchorProps}
{...contextHoverProps}
>
{/*
Expand Down Expand Up @@ -483,8 +445,6 @@ function renderRangeChildren(
controller: PathStoreTreesController,
range: { start: number; end: number },
activeItemPath: string | null,
contextAnchorName: string | null,
contextAnchorPath: string | null,
contextHoverPath: string | null,
itemHeight: number,
contextMenuEnabled: boolean,
Expand Down Expand Up @@ -515,8 +475,6 @@ function renderRangeChildren(
controller,
row,
activeItemPath,
contextAnchorName,
contextAnchorPath,
contextHoverPath,
itemHeight,
contextMenuEnabled,
Expand Down Expand Up @@ -589,8 +547,6 @@ export function PathStoreTreesView({
composition?.contextMenu?.render != null ||
composition?.contextMenu?.onOpen != null ||
composition?.contextMenu?.onClose != null;
const contextMenuUsesAnchorPositioning =
supportsContextMenuAnchorPositioning();
const { resolveIcon } = useMemo(
() => createPathStoreIconResolver(icons),
[icons]
Expand Down Expand Up @@ -647,11 +603,6 @@ export function PathStoreTreesView({
closeContextMenuRef.current = closeContextMenu;
const updateTriggerPosition = useCallback(
(itemButton: HTMLButtonElement | null): void => {
if (contextMenuUsesAnchorPositioning) {
setContextMenuAnchorTop(null);
return;
}

const nextTop =
itemButton == null
? null
Expand All @@ -660,7 +611,7 @@ export function PathStoreTreesView({
previousTop === nextTop ? previousTop : nextTop
);
},
[contextMenuUsesAnchorPositioning]
[]
);
const openContextMenuForRow = useCallback(
(row: PathStoreTreesVisibleRow, targetPath: string): void => {
Expand Down Expand Up @@ -1185,12 +1136,7 @@ export function PathStoreTreesView({
const guideStyleText = getPathStoreGuideStyleText(
focusedVisibleRow?.ancestorPaths.at(-1) ?? null
);
const contextAnchorName =
contextMenuUsesAnchorPositioning && triggerPath != null
? CONTEXT_MENU_ROW_ANCHOR_NAME
: null;
const visualFocusPath = contextMenuState?.path ?? activeItemPath;
const contextAnchorPath = triggerPath;
const visualContextHoverPath = contextMenuState?.path ?? contextHoverPath;
const triggerButton =
triggerPath == null
Expand All @@ -1199,21 +1145,14 @@ export function PathStoreTreesView({
const triggerButtonVisible =
contextMenuEnabled &&
triggerButton != null &&
triggerPath != null &&
(contextMenuUsesAnchorPositioning || contextMenuAnchorTop != null);
contextMenuAnchorTop != null &&
triggerPath != null;
const contextMenuAnchorStyle =
contextMenuUsesAnchorPositioning && contextAnchorName != null
triggerButtonVisible && contextMenuAnchorTop != null
? {
positionAnchor: contextAnchorName,
top: 'anchor(top)',
top: `${contextMenuAnchorTop}px`,
}
: !contextMenuUsesAnchorPositioning &&
triggerButtonVisible &&
contextMenuAnchorTop != null
? {
top: `${contextMenuAnchorTop}px`,
}
: undefined;
: undefined;
const openMenuFromTrigger = (): void => {
if (triggerPath == null || triggerButton == null) {
return;
Expand Down Expand Up @@ -1278,8 +1217,6 @@ export function PathStoreTreesView({
controller,
range,
visualFocusPath,
contextAnchorName,
contextAnchorPath,
visualContextHoverPath,
itemHeight,
contextMenuEnabled,
Expand All @@ -1301,8 +1238,6 @@ export function PathStoreTreesView({
controller,
parkedFocusedRow,
visualFocusPath,
contextAnchorName,
contextAnchorPath,
visualContextHoverPath,
itemHeight,
contextMenuEnabled,
Expand Down Expand Up @@ -1336,9 +1271,6 @@ export function PathStoreTreesView({
<div
ref={contextMenuAnchorRef}
data-type="context-menu-anchor"
data-anchor-positioning={
contextMenuUsesAnchorPositioning ? 'true' : undefined
}
data-visible={triggerButtonVisible ? 'true' : 'false'}
style={contextMenuAnchorStyle}
>
Expand Down
77 changes: 77 additions & 0 deletions packages/trees/test/e2e/path-store-composition.pw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,83 @@ async function pressFocusedRowKey(page: Page, key: string): Promise<void> {
}

test.describe('path-store composition surfaces', () => {
test('hovering a scrolled tree does not change the visible slice or scroll position', async ({
page,
}) => {
await page.goto('/test/e2e/fixtures/path-store-composition.html');
await page.waitForFunction(
() => window.__pathStoreCompositionFixtureReady === true
);

const measurement = await page.evaluate(async () => {
const host = document.querySelector('file-tree-container');
const shadowRoot = host?.shadowRoot;
const scroll = shadowRoot?.querySelector(
'[data-file-tree-virtualized-scroll="true"]'
);
if (!(scroll instanceof HTMLElement)) {
return null;
}

const nextFrame = () =>
new Promise<void>((resolve) => {
requestAnimationFrame(() => resolve());
});

const pickPaths = [
'src/lib/theme.ts',
'src/lib/utils.ts',
'src/index.ts',
'README.md',
];
const measure = () => ({
rows: pickPaths.map((path) => {
const row = shadowRoot?.querySelector(
`button[data-item-path="${path}"]`
);
return row instanceof HTMLElement
? {
path,
top: row.getBoundingClientRect().top,
}
: {
path,
top: null,
};
}),
scrollTop: scroll.scrollTop,
});

scroll.scrollTop = 60;
await nextFrame();
await nextFrame();

const before = measure();
const hoverRow = shadowRoot?.querySelector(
'button[data-item-path="src/index.ts"]'
);
if (!(hoverRow instanceof HTMLElement)) {
return { before, after: null };
}

hoverRow.dispatchEvent(
new PointerEvent('pointerover', { bubbles: true, composed: true })
);
await nextFrame();
await nextFrame();

return {
after: measure(),
before,
};
});

expect(measurement).not.toBeNull();
expect(measurement?.after).not.toBeNull();
expect(measurement?.after?.scrollTop).toBe(measurement?.before.scrollTop);
expect(measurement?.after?.rows).toEqual(measurement?.before.rows);
});

test('moves the floating trigger when the active row changes', async ({
page,
}) => {
Expand Down
96 changes: 0 additions & 96 deletions packages/trees/test/e2e/path-store-docs-anchor.pw.ts

This file was deleted.

Loading
Loading