|
97 | 97 | } |
98 | 98 | } |
99 | 99 | customElements.define('position-anchor-on-host', PositionAnchorOnHost); |
| 100 | + |
| 101 | + // `position-area` in a `:host` rule positions the shadow *host*, which |
| 102 | + // lives in the outer tree rather than in the shadow root the rule came |
| 103 | + // from. The styles the polyfill generates to map the computed insets |
| 104 | + // onto the target have to be inserted into that outer tree to match it. |
| 105 | + const positionAreaOnHostSheet = new CSSStyleSheet(); |
| 106 | + positionAreaOnHostSheet.replaceSync(` |
| 107 | + :host { |
| 108 | + --element-color: var(--target, var(--outer-anchored)); |
| 109 | + background: var(--element-color); |
| 110 | + border: thin solid var(--border); |
| 111 | + border-radius: var(--radius-1); |
| 112 | + color: white; |
| 113 | + font-weight: bold; |
| 114 | + padding: 0.5em; |
| 115 | + white-space: nowrap; |
| 116 | + position: absolute; |
| 117 | + position-area: top; |
| 118 | + } |
| 119 | + `); |
| 120 | + |
| 121 | + class PositionAreaOnHost extends HTMLElement { |
| 122 | + connectedCallback() { |
| 123 | + // Moving the host into the `position-area` wrapper disconnects and |
| 124 | + // reconnects it, so this runs more than once. |
| 125 | + if (this.shadowRoot) return; |
| 126 | + |
| 127 | + this.attachShadow({ mode: 'open' }); |
| 128 | + this.shadowRoot.adoptedStyleSheets = [positionAreaOnHostSheet]; |
| 129 | + this.shadowRoot.innerHTML = '<slot></slot>'; |
| 130 | + } |
| 131 | + } |
| 132 | + customElements.define('position-area-on-host', PositionAreaOnHost); |
100 | 133 | } |
101 | 134 |
|
102 | 135 | const btn = document.getElementById('apply-polyfill'); |
@@ -478,6 +511,70 @@ <h2> |
478 | 511 | } |
479 | 512 | customElements.define("position-anchor-on-host", PositionAnchorOnHost); |
480 | 513 | </script> |
| 514 | +</code></pre> |
| 515 | + </section> |
| 516 | + <section id="position-area-on-host" class="demo-item"> |
| 517 | + <h2> |
| 518 | + <a href="#position-area-on-host" aria-hidden="true">🔗</a> |
| 519 | + Works when a custom element host has <code>position-area</code> |
| 520 | + </h2> |
| 521 | + <div style="position: relative" class="demo-elements"> |
| 522 | + <div |
| 523 | + class="anchor" |
| 524 | + style=" |
| 525 | + anchor-name: --position-area-on-host; |
| 526 | + margin-block-start: calc(1lh + 1rem); |
| 527 | + " |
| 528 | + > |
| 529 | + Anchor |
| 530 | + </div> |
| 531 | + <position-area-on-host style="position-anchor: --position-area-on-host" |
| 532 | + >Target</position-area-on-host |
| 533 | + > |
| 534 | + </div> |
| 535 | + <div class="note"> |
| 536 | + <p>With polyfill applied: Target sits directly above the Anchor.</p> |
| 537 | + <p> |
| 538 | + The <code>position-area</code> is declared in a |
| 539 | + <code>:host</code> rule, so the element it positions is the host |
| 540 | + (<code><position-area-on-host></code>), which lives in the outer |
| 541 | + tree rather than in the shadow root the rule came from. The styles the |
| 542 | + polyfill generates to map the computed insets onto the target are |
| 543 | + inserted into the host's own tree; a <code><style></code> inside |
| 544 | + the shadow root would never match the host. |
| 545 | + </p> |
| 546 | + </div> |
| 547 | + |
| 548 | + <pre><code class="language-html" |
| 549 | +><div class="anchor" style="anchor-name: --position-area-on-host">Anchor</div> |
| 550 | +<position-area-on-host style="position-anchor: --position-area-on-host">Target</position-area-on-host> |
| 551 | +<script> |
| 552 | +<!-- Load the shadow entrypoint before defining custom elements, |
| 553 | +so the replaceSync and adoptedStyleSheets patches are installed |
| 554 | +before any connectedCallback runs. --> |
| 555 | +import { patchAndPolyfillConstructedStylesheets } from '@oddbird/css-anchor-positioning/fn'; |
| 556 | +patchAndPolyfillConstructedStylesheets(); |
| 557 | + |
| 558 | +class PositionAreaOnHost extends HTMLElement { |
| 559 | + connectedCallback() { |
| 560 | + // Moving the host into the position-area wrapper reconnects it. |
| 561 | + if (this.shadowRoot) return; |
| 562 | + |
| 563 | + this.attachShadow({ mode: "open" }); |
| 564 | + |
| 565 | + const sheet = new CSSStyleSheet(); |
| 566 | + sheet.replaceSync(` |
| 567 | + :host { |
| 568 | + position: absolute; |
| 569 | + position-area: top; |
| 570 | + } |
| 571 | + `); |
| 572 | + this.shadowRoot.adoptedStyleSheets = [sheet]; |
| 573 | + this.shadowRoot.innerHTML = "<slot></slot>"; |
| 574 | + } |
| 575 | +} |
| 576 | +customElements.define("position-area-on-host", PositionAreaOnHost); |
| 577 | +</script> |
481 | 578 | </code></pre> |
482 | 579 | </section> |
483 | 580 | <section id="sponsor"> |
|
0 commit comments