Skip to content

Commit

Permalink
fix: handle first and last child attributes properly, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan committed Jan 16, 2025
1 parent 8c881f9 commit 7dbe735
Show file tree
Hide file tree
Showing 2 changed files with 201 additions and 10 deletions.
37 changes: 27 additions & 10 deletions packages/horizontal-layout/src/vaadin-horizontal-layout-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ export const HorizontalLayoutMixin = (superClass) =>

const children = currentNodes.filter((node) => node.nodeType === Node.ELEMENT_NODE);

if (children.length) {
children[children.length - 1].setAttribute('last-start-child', '');
}
children.forEach((child, idx) => {
if (idx === children.length - 1) {
child.setAttribute('last-start-child', '');
} else if (child.hasAttribute('last-start-child')) {
child.removeAttribute('last-start-child');
}
});

const nodes = currentNodes.filter((node) => !isEmptyTextNode(node));
this.toggleAttribute('has-start', nodes.length > 0);
Expand All @@ -49,9 +53,13 @@ export const HorizontalLayoutMixin = (superClass) =>
}
}

if (currentNodes.length) {
currentNodes[0].setAttribute('first-end-child', '');
}
currentNodes.forEach((child, idx) => {
if (idx === 0) {
child.setAttribute('first-end-child', '');
} else if (child.hasAttribute('first-end-child')) {
child.removeAttribute('first-end-child');
}
});

this.toggleAttribute('has-end', currentNodes.length > 0);

Expand All @@ -72,10 +80,19 @@ export const HorizontalLayoutMixin = (superClass) =>
}
}

if (currentNodes.length) {
currentNodes[0].setAttribute('first-middle-child', '');
currentNodes[currentNodes.length - 1].setAttribute('last-middle-child', '');
}
currentNodes.forEach((child, idx) => {
if (idx === 0) {
child.setAttribute('first-middle-child', '');
} else if (child.hasAttribute('first-middle-child')) {
child.removeAttribute('first-middle-child');
}

if (idx === currentNodes.length - 1) {
child.setAttribute('last-middle-child', '');
} else if (child.hasAttribute('last-middle-child')) {
child.removeAttribute('last-middle-child');
}
});

this.toggleAttribute('has-middle', currentNodes.length > 0);

Expand Down
174 changes: 174 additions & 0 deletions packages/horizontal-layout/test/horizontal-layout.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,178 @@ describe('vaadin-horizontal-layout', () => {
expect(wrapper.scrollWidth).to.equal(200);
});
});

describe('slots', () => {
let layout;

beforeEach(() => {
layout = fixtureSync('<vaadin-horizontal-layout></vaadin-horizontal-layout>');
});

describe('start', () => {
it('should set has-start attribute when element added to default slot', async () => {
const div = document.createElement('div');
layout.appendChild(div);
await nextFrame();
expect(layout.hasAttribute('has-start')).to.be.true;
});

it('should remove has-start attribute when element removed from default slot', async () => {
const div = document.createElement('div');
layout.appendChild(div);
await nextFrame();

layout.removeChild(div);
await nextFrame();
expect(layout.hasAttribute('has-start')).to.be.false;
});

it('should set last-start-child attribute on last element in the default slot', async () => {
const div = document.createElement('div');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('last-start-child')).to.be.true;

const other = document.createElement('div');
layout.appendChild(other);
await nextFrame();
expect(div.hasAttribute('last-start-child')).to.be.false;
expect(other.hasAttribute('last-start-child')).to.be.true;
});

it('should remove last-start-child attribute when element is removed', async () => {
const div = document.createElement('div');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('last-start-child')).to.be.true;

layout.removeChild(div);
await nextFrame();
expect(div.hasAttribute('last-start-child')).to.be.false;
});
});

describe('middle', () => {
it('should set has-middle attribute when element added to middle slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'middle');
layout.appendChild(div);
await nextFrame();
expect(layout.hasAttribute('has-middle')).to.be.true;
});

it('should remove has-middle attribute when element removed from middle slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'middle');
layout.appendChild(div);
await nextFrame();

layout.removeChild(div);
await nextFrame();
expect(layout.hasAttribute('has-middle')).to.be.false;
});

it('should set first-middle-child attribute on first element in the middle slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'middle');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('first-middle-child')).to.be.true;

const other = document.createElement('div');
other.setAttribute('slot', 'middle');
layout.insertBefore(other, div);
await nextFrame();
expect(div.hasAttribute('first-middle-child')).to.be.false;
expect(other.hasAttribute('first-middle-child')).to.be.true;
});

it('should set last-middle-child attribute on last element in the middle slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'middle');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('last-middle-child')).to.be.true;

const other = document.createElement('div');
other.setAttribute('slot', 'middle');
layout.appendChild(other);
await nextFrame();
expect(div.hasAttribute('last-middle-child')).to.be.false;
expect(other.hasAttribute('last-middle-child')).to.be.true;
});

it('should remove first-middle-child attribute when element is removed', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'middle');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('first-middle-child')).to.be.true;

layout.removeChild(div);
await nextFrame();
expect(div.hasAttribute('first-middle-child')).to.be.false;
});

it('should remove last-middle-child attribute when element is removed', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'middle');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('last-middle-child')).to.be.true;

layout.removeChild(div);
await nextFrame();
expect(div.hasAttribute('last-middle-child')).to.be.false;
});
});

describe('end', () => {
it('should set has-end attribute when element added to end slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'end');
layout.appendChild(div);
await nextFrame();
expect(layout.hasAttribute('has-end')).to.be.true;
});

it('should remove has-end attribute when element removed from end slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'end');
layout.appendChild(div);
await nextFrame();

layout.removeChild(div);
await nextFrame();
expect(layout.hasAttribute('has-end')).to.be.false;
});

it('should set first-end-child attribute on first element in the end slot', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'end');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('first-end-child')).to.be.true;

const other = document.createElement('div');
other.setAttribute('slot', 'end');
layout.insertBefore(other, div);
await nextFrame();
expect(div.hasAttribute('first-end-child')).to.be.false;
expect(other.hasAttribute('first-end-child')).to.be.true;
});

it('should remove first-end-child attribute when element is removed', async () => {
const div = document.createElement('div');
div.setAttribute('slot', 'end');
layout.appendChild(div);
await nextFrame();
expect(div.hasAttribute('first-end-child')).to.be.true;

layout.removeChild(div);
await nextFrame();
expect(div.hasAttribute('first-end-child')).to.be.false;
});
});
});
});

0 comments on commit 7dbe735

Please sign in to comment.