Skip to content

Commit

Permalink
Merge pull request #90 from oddbird/top-layer
Browse files Browse the repository at this point in the history
Adding support for top-layer
  • Loading branch information
jgerigmeyer authored Mar 27, 2023
2 parents 2528b2c + 46b3b0a commit f6d4e2d
Show file tree
Hide file tree
Showing 5 changed files with 428 additions and 6 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,19 @@ option can be set by setting the value of

This polyfill doesn't (yet) support the following:

- top layer anchor elements
- `anchor-default` property
- `anchor-scroll` property
- anchor functions with `implicit` anchor-element
- automatic anchor positioning: anchor functions with `auto` or `auto-same`
anchor-side
- dynamically added/removed anchors or targets
- anchors or targets in the shadow-dom
- tracking the order of elements in the
[top-layer](https://fullscreen.spec.whatwg.org/#new-stacking-layer) to
invalidate top-layer target elements from anchoring to succeeding top-layer
anchors. See [this
WPT](https://github.com/web-platform-tests/wpt/blob/master/css/css-anchor-position/anchor-position-top-layer-006.html)
for an example.
- anchor functions assigned to `inset-*` properties or `inset` shorthand
property
- vertical/rtl writing-modes (partial support)
Expand Down
45 changes: 45 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@
rel="stylesheet"
href="https://unpkg.com/prismjs@v1.x/themes/prism.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.css"
crossorigin="anonymous"
/>
<script
src="https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js"
crossorigin="anonymous"
defer
></script>
<link rel="stylesheet" href="/demo.css" />
<link rel="stylesheet" href="/anchor.css" />
<link rel="stylesheet" href="/anchor-positioning.css" />
<link rel="stylesheet" href="/anchor-popover.css" />
<link rel="stylesheet" href="/position-fallback.css" />
<link rel="stylesheet" href="/anchor-scroll.css" />
<link rel="stylesheet" href="/anchor-size.css" />
Expand Down Expand Up @@ -283,6 +294,40 @@ <h2>
position: absolute;
right: anchor(implicit left);
bottom: anchor(top);
}</code></pre>
</section>
<section id="anchor-positioning-popover" class="demo-item">
<h2>
<a href="#anchor-positioning-popover" aria-hidden="true">🔗</a>
Anchoring a <code>popover</code>
</h2>
<div style="position: relative" class="demo-elements">
<div id="my-target-popover" class="target" popover="auto">
Popover (Target)
</div>
<button
id="my-anchor-popover"
class="anchor"
popovertarget="my-target-popover"
>
Anchor (click to open)
</button>
</div>
<p class="note">
With polyfill applied: Target is positioned at the bottom right corner
of the Anchor.
</p>
<pre><code class="language-css"
>#my-anchor-popover {
position: absolute;
left: 200px;
anchor-name: --my-anchor-popover;
}

#my-target-popover {
position: absolute;
left: anchor(--my-anchor-popover right);
top: anchor(--my-anchor-popover bottom);
}</code></pre>
</section>
<section id="custom-prop-name" class="demo-item">
Expand Down
12 changes: 12 additions & 0 deletions public/anchor-popover.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#my-anchor-popover {
position: absolute;
left: 200px;
anchor-name: --my-anchor-popover;
}

#my-target-popover {
position: absolute;
margin: 0;
left: anchor(--my-anchor-popover right);
top: anchor(--my-anchor-popover bottom);
}
32 changes: 27 additions & 5 deletions src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,43 @@ function isAbsolutelyPositioned(el?: HTMLElement | null) {
);
}

function isTopLayer(el: HTMLElement) {
// check for the specific top layer element types...
// Currently, the top layer elements are:
// popovers, modal dialogs, and elements in a fullscreen mode.
// See https://developer.chrome.com/blog/top-layer-devtools/#what-are-the-top-layer-and-top-layer-elements
// TODO:
// - only check for "open" popovers
// - add support for fullscreen elements
const topLayerElements = document.querySelectorAll('dialog, [popover]');
return Boolean(Array.from(topLayerElements).includes(el));
}

// Validates that anchor element is a valid anchor for given target element
export async function isValidAnchorElement(
anchor: HTMLElement,
target: HTMLElement,
) {
if (isTopLayer(anchor) && isTopLayer(target)) {
// TODO: keep track of top layer order
// if (isTargetPrecedingAnchor(target, anchor)) {
// return false;
// }
return true;
}

const anchorContainingBlock = await platform.getOffsetParent?.(anchor);
const targetContainingBlock = await platform.getOffsetParent?.(target);

// If el has the same containing block as the querying element,
// el must not be absolutely positioned.
if (
isAbsolutelyPositioned(anchor) &&
anchorContainingBlock === targetContainingBlock
) {
return false;
if (isAbsolutelyPositioned(anchor)) {
if (isTopLayer(target)) {
return true;
}
if (anchorContainingBlock === targetContainingBlock) {
return false;
}
}

// If el has a different containing block from the querying element,
Expand Down
Loading

0 comments on commit f6d4e2d

Please sign in to comment.