Skip to content

Commit 0c93eac

Browse files
committed
Support list of anchor names
1 parent ca104d3 commit 0c93eac

File tree

4 files changed

+124
-13
lines changed

4 files changed

+124
-13
lines changed

index.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<link rel="stylesheet" href="/anchor-size.css" />
3030
<link rel="stylesheet" href="/anchor-math.css" />
3131
<link rel="stylesheet" href="/anchor-name-custom-prop.css" />
32+
<link rel="stylesheet" href="/anchor-name-list.css" />
3233
<link rel="stylesheet" href="/anchor-custom-props.css" />
3334
<link rel="stylesheet" href="/anchor-duplicate-custom-props.css" />
3435
<link rel="stylesheet" href="/anchor-implicit.css" />
@@ -664,6 +665,38 @@ <h2>
664665
right: anchor(--my-anchor-update right);
665666
top: anchor(--my-anchor-update bottom);
666667
}</code></pre>
668+
</section>
669+
<section id="anchor-name-list" class="demo-item">
670+
<h2>
671+
<a href="#anchor-name-list" aria-hidden="true">🔗</a>
672+
Use a list of anchor names
673+
</h2>
674+
<div style="position: relative" class="demo-elements">
675+
<div id="my-anchor-name-list" class="anchor">Anchor</div>
676+
<div id="my-target-name-list-a" class="target">Target A</div>
677+
<div id="my-target-name-list-b" class="target">Target B</div>
678+
</div>
679+
<p class="note">
680+
With polyfill applied: Target A is positioned at Anchor's top left
681+
corner. Target B is positioned at Anchor's bottom right corner.
682+
</p>
683+
<pre><code class="language-css"
684+
>#my-anchor-name-list {
685+
anchor-name: --my-anchor-name-a, --my-anchor-name-b;
686+
}
687+
688+
#my-target-name-list-a {
689+
position: absolute;
690+
right: anchor(--my-anchor-name-a left);
691+
bottom: anchor(--my-anchor-name-a top);
692+
}
693+
694+
#my-target-name-list-b {
695+
position: absolute;
696+
left: anchor(--my-anchor-name-b right);
697+
top: anchor(--my-anchor-name-b bottom);
698+
}
699+
</code></pre>
667700
</section>
668701
<section id="sponsor">
669702
<h2>Sponsor OddBird's OSS Work</h2>

public/anchor-name-list.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#my-anchor-name-list {
2+
anchor-name: --my-anchor-name-a, --my-anchor-name-b;
3+
}
4+
5+
#my-target-name-list-a {
6+
position: absolute;
7+
right: anchor(--my-anchor-name-a left);
8+
bottom: anchor(--my-anchor-name-a top);
9+
}
10+
11+
#my-target-name-list-b {
12+
position: absolute;
13+
left: anchor(--my-anchor-name-b right);
14+
top: anchor(--my-anchor-name-b bottom);
15+
}

src/parse.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,12 @@ function getAnchorNameData(node: csstree.CssNode, rule?: csstree.Raw) {
338338
node.value.children.first &&
339339
rule?.value
340340
) {
341-
const name = (node.value.children.first as csstree.Identifier).name;
342-
return { name, selector: rule.value };
341+
return node.value.children.map((item) => {
342+
const { name } = item as csstree.Identifier;
343+
return { name, selector: rule.value };
344+
});
343345
}
344-
return {};
346+
return [];
345347
}
346348

347349
let anchorNames: AnchorNames = {};
@@ -559,17 +561,18 @@ export async function parseCSS(styleData: StyleData[]) {
559561
const rule = this.rule?.prelude as csstree.Raw | undefined;
560562

561563
// Parse `anchor-name` declaration
562-
const { name: anchorName, selector: anchorSelector } = getAnchorNameData(
563-
node,
564-
rule,
564+
const anchorNameData = getAnchorNameData(node, rule);
565+
anchorNameData.forEach(
566+
({ name: anchorName, selector: anchorSelector }) => {
567+
if (anchorName && anchorSelector) {
568+
if (anchorNames[anchorName]) {
569+
anchorNames[anchorName].push(anchorSelector);
570+
} else {
571+
anchorNames[anchorName] = [anchorSelector];
572+
}
573+
}
574+
},
565575
);
566-
if (anchorName && anchorSelector) {
567-
if (anchorNames[anchorName]) {
568-
anchorNames[anchorName].push(anchorSelector);
569-
} else {
570-
anchorNames[anchorName] = [anchorSelector];
571-
}
572-
}
573576

574577
// Parse `anchor()` function
575578
const {

tests/unit/parse.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,66 @@ describe('parseCSS', () => {
341341
expect(rules).toEqual(expected);
342342
});
343343

344+
it('parses `anchor-name` with a list of names', async () => {
345+
document.body.innerHTML =
346+
'<div style="position: relative"><div id="my-anchor-name-list"></div><div id="my-target-name-list-a"></div><div id="my-target-name-list-b"></div></div>';
347+
const css = getSampleCSS('anchor-name-list');
348+
document.head.innerHTML = `<style>${css}</style>`;
349+
const { rules } = await parseCSS([{ css }] as StyleData[]);
350+
const expected = {
351+
'#my-target-name-list-a': {
352+
declarations: {
353+
right: [
354+
{
355+
anchorSide: 'left',
356+
anchorEl: document.getElementById('my-anchor-name-list'),
357+
targetEl: document.getElementById('my-target-name-list-a'),
358+
anchorName: '--my-anchor-name-a',
359+
fallbackValue: '0px',
360+
uuid: expect.any(String),
361+
},
362+
],
363+
bottom: [
364+
{
365+
anchorSide: 'top',
366+
anchorEl: document.getElementById('my-anchor-name-list'),
367+
targetEl: document.getElementById('my-target-name-list-a'),
368+
anchorName: '--my-anchor-name-a',
369+
fallbackValue: '0px',
370+
uuid: expect.any(String),
371+
},
372+
],
373+
},
374+
},
375+
'#my-target-name-list-b': {
376+
declarations: {
377+
left: [
378+
{
379+
anchorSide: 'right',
380+
anchorEl: document.getElementById('my-anchor-name-list'),
381+
targetEl: document.getElementById('my-target-name-list-b'),
382+
anchorName: '--my-anchor-name-b',
383+
fallbackValue: '0px',
384+
uuid: expect.any(String),
385+
},
386+
],
387+
top: [
388+
{
389+
anchorSide: 'bottom',
390+
anchorEl: document.getElementById('my-anchor-name-list'),
391+
targetEl: document.getElementById('my-target-name-list-b'),
392+
anchorName: '--my-anchor-name-b',
393+
fallbackValue: '0px',
394+
uuid: expect.any(String),
395+
},
396+
],
397+
},
398+
},
399+
};
400+
401+
expect(rules).toEqual(expected);
402+
});
403+
344404
it('parses `anchor()` function (math)', async () => {
345405
document.body.innerHTML =
346406
'<div style="position: relative"><div id="my-target-math"></div><div id="my-anchor-math"></div></div>';

0 commit comments

Comments
 (0)