Skip to content

Commit 017f278

Browse files
yanlingwang23Devtools-frontend LUCI CQ
authored andcommitted
[Masonry] Adding support for masonry adorners in the Elements tree
This CL adds [masonry] adorners to the Elements DOM tree, similar to the implementation we previously did for Grid. Screenshots: https://imgur.com/a/Nqy6J9F Bug: 343257585, 40159741 Change-Id: I660bd38c3b22fdbaea1ccaa47881f8050e7ce512 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6833016 Reviewed-by: Simon Zünd <[email protected]> Reviewed-by: Changhao Han <[email protected]> Commit-Queue: Yanling Wang <[email protected]>
1 parent ee29619 commit 017f278

File tree

7 files changed

+92
-0
lines changed

7 files changed

+92
-0
lines changed

front_end/core/sdk/CSSModel.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export interface LayoutProperties {
6767
isFlex: boolean;
6868
isGrid: boolean;
6969
isSubgrid: boolean;
70+
isMasonry: boolean;
7071
isContainer: boolean;
7172
hasScroll: boolean;
7273
}
@@ -421,6 +422,7 @@ export class CSSModel extends SDKModel<EventTypes> {
421422
(styles.get('grid-template-columns')?.startsWith('subgrid') ||
422423
styles.get('grid-template-rows')?.startsWith('subgrid'))) ??
423424
false;
425+
const isMasonry = display === 'masonry' || display === 'inline-masonry';
424426
const containerType = styles.get('container-type');
425427
const isContainer = Boolean(containerType) && containerType !== '' && containerType !== 'normal';
426428
const hasScroll = Boolean(styles.get('scroll-snap-type')) && styles.get('scroll-snap-type') !== 'none';
@@ -429,6 +431,7 @@ export class CSSModel extends SDKModel<EventTypes> {
429431
isFlex,
430432
isGrid,
431433
isSubgrid,
434+
isMasonry,
432435
isContainer,
433436
hasScroll,
434437
};

front_end/panels/elements/ElementsTreeElement.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ describeWithMockConnection('ElementsTreeElement ', () => {
125125
isFlex: false,
126126
isGrid: false,
127127
isSubgrid: false,
128+
isMasonry: false,
128129
isContainer: false,
129130
hasScroll: false,
130131
};

front_end/panels/elements/ElementsTreeElement.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,14 @@ const UIStrings = {
185185
* @description ARIA label for Elements Tree adorners
186186
*/
187187
disableGridMode: 'Disable grid mode',
188+
/**
189+
* @description ARIA label for Elements Tree adorners
190+
*/
191+
enableMasonryMode: 'Enable masonry mode',
192+
/**
193+
* @description ARIA label for Elements Tree adorners
194+
*/
195+
disableMasonryMode: 'Disable masonry mode',
188196
/**
189197
* @description ARIA label for an elements tree adorner
190198
*/
@@ -2504,6 +2512,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
25042512
if (layout.isGrid) {
25052513
this.pushGridAdorner(this.tagTypeContext, layout.isSubgrid);
25062514
}
2515+
if (layout.isMasonry) {
2516+
this.pushMasonryAdorner(this.tagTypeContext);
2517+
}
25072518
if (layout.isFlex) {
25082519
this.pushFlexAdorner(this.tagTypeContext);
25092520
}
@@ -2598,6 +2609,47 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
25982609
}
25992610
}
26002611

2612+
pushMasonryAdorner(context: OpeningTagContext): void {
2613+
const node = this.node();
2614+
const nodeId = node.id;
2615+
if (!nodeId) {
2616+
return;
2617+
}
2618+
2619+
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
2620+
ElementsComponents.AdornerManager.RegisteredAdorners.MASONRY);
2621+
const adorner = this.adorn(config);
2622+
adorner.classList.add('masonry');
2623+
2624+
const onClick = ((() => {
2625+
if (adorner.isActive()) {
2626+
node.domModel().overlayModel().highlightGridInPersistentOverlay(nodeId);
2627+
} else {
2628+
node.domModel().overlayModel().hideGridInPersistentOverlay(nodeId);
2629+
}
2630+
}) as EventListener);
2631+
adorner.addInteraction(onClick, {
2632+
isToggle: true,
2633+
shouldPropagateOnKeydown: false,
2634+
ariaLabelDefault: i18nString(UIStrings.enableMasonryMode),
2635+
ariaLabelActive: i18nString(UIStrings.disableMasonryMode),
2636+
});
2637+
2638+
node.domModel().overlayModel().addEventListener(
2639+
SDK.OverlayModel.Events.PERSISTENT_GRID_OVERLAY_STATE_CHANGED, event => {
2640+
const {nodeId: eventNodeId, enabled} = event.data;
2641+
if (eventNodeId !== nodeId) {
2642+
return;
2643+
}
2644+
adorner.toggle(enabled);
2645+
});
2646+
2647+
context.styleAdorners.add(adorner);
2648+
if (node.domModel().overlayModel().isHighlightedGridInPersistentOverlay(nodeId)) {
2649+
adorner.toggle(true);
2650+
}
2651+
}
2652+
26012653
pushScrollSnapAdorner(context: OpeningTagContext): void {
26022654
const node = this.node();
26032655
const nodeId = node.id;

front_end/panels/elements/components/AdornerManager.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface RegisteredAdorner {
2424
export enum RegisteredAdorners {
2525
GRID = 'grid',
2626
SUBGRID = 'subgrid',
27+
MASONRY = 'masonry',
2728
FLEX = 'flex',
2829
AD = 'ad',
2930
SCROLL_SNAP = 'scroll-snap',
@@ -52,6 +53,12 @@ export function getRegisteredAdorner(which: RegisteredAdorners): RegisteredAdorn
5253
category: AdornerCategories.LAYOUT,
5354
enabledByDefault: true,
5455
};
56+
case RegisteredAdorners.MASONRY:
57+
return {
58+
name: 'masonry',
59+
category: AdornerCategories.LAYOUT,
60+
enabledByDefault: true,
61+
};
5562
case RegisteredAdorners.FLEX:
5663
return {
5764
name: 'flex',

test/e2e/resources/elements/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ copy_to_gen("elements") {
99
"accessibility-iframe-page.html",
1010
"accessibility-simple-page.html",
1111
"adornment-container-query.html",
12+
"adornment-masonry.html",
1213
"adornment-media.html",
1314
"adornment-scroll-snap.html",
1415
"adornment-scroll.html",
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!--
2+
Copyright 2025 The Chromium Authors. All rights reserved.
3+
Use of this source code is governed by a BSD-style license that can be
4+
found in the LICENSE file.
5+
-->
6+
<!DOCTYPE html>
7+
<style>
8+
.masonry {
9+
display: masonry;
10+
}
11+
.inline-masonry {
12+
display: inline-masonry;
13+
}
14+
</style>
15+
<div class="masonry"></div>
16+
<div class="inline-masonry"></div>

test/e2e_non_hosted/elements/adornment_test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ describe('Adornment in the Elements Tab', function() {
4545
devToolsPage);
4646
});
4747

48+
it('displays masonry adorners', async ({devToolsPage, inspectedPage}) => {
49+
await inspectedPage.goToResource('elements/adornment-masonry.html');
50+
await prepareElementsTab(devToolsPage);
51+
52+
await waitForAdorners(
53+
[
54+
{textContent: 'masonry', isActive: false},
55+
{textContent: 'masonry', isActive: false},
56+
],
57+
devToolsPage);
58+
});
59+
4860
it('displays scroll-snap adorners', async ({devToolsPage, inspectedPage}) => {
4961
await inspectedPage.goToResource('elements/adornment-scroll-snap.html');
5062
await prepareElementsTab(devToolsPage);

0 commit comments

Comments
 (0)