-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add basic dashboard widget structure (#7679)
- Loading branch information
1 parent
19ccbe9
commit 3443482
Showing
7 changed files
with
315 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* @license | ||
* Copyright (c) 2019 - 2024 Vaadin Ltd. | ||
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ | ||
*/ | ||
import { SlotChildObserveController } from '@vaadin/component-base/src/slot-child-observe-controller.js'; | ||
|
||
/** | ||
* A controller to manage the widget title element. | ||
*/ | ||
export class TitleController extends SlotChildObserveController { | ||
/** | ||
* String used for the widget title. | ||
*/ | ||
protected widgetTitle: string | null | undefined; | ||
|
||
/** | ||
* Set widget title based on corresponding host property. | ||
*/ | ||
setWidgetTitle(widgetTitle: string | null | undefined): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* @license | ||
* Copyright (c) 2019 - 2024 Vaadin Ltd. | ||
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ | ||
*/ | ||
import { SlotChildObserveController } from '@vaadin/component-base/src/slot-child-observe-controller.js'; | ||
|
||
/** | ||
* A controller to manage the widget title element. | ||
*/ | ||
export class TitleController extends SlotChildObserveController { | ||
constructor(host) { | ||
super(host, 'title', null); | ||
} | ||
|
||
/** | ||
* Set widget title based on corresponding host property. | ||
* | ||
* @param {string} widgetTitle | ||
*/ | ||
setWidgetTitle(widgetTitle) { | ||
this.widgetTitle = widgetTitle; | ||
|
||
// Restore the default widgetTitle, if needed. | ||
const widgetTitleNode = this.getSlotChild(); | ||
if (!widgetTitleNode) { | ||
this.restoreDefaultNode(); | ||
} | ||
|
||
// When default widgetTitle is used, update it. | ||
if (this.node === this.defaultNode) { | ||
this.updateDefaultNode(this.node); | ||
} | ||
} | ||
|
||
/** | ||
* Override method inherited from `SlotChildObserveController` | ||
* to restore and observe the default widget title element. | ||
* | ||
* @protected | ||
* @override | ||
*/ | ||
restoreDefaultNode() { | ||
this.tagName = 'h2'; | ||
this.attachDefaultNode(); | ||
} | ||
|
||
/** | ||
* Override method inherited from `SlotChildObserveController` | ||
* to update the default widgetTitle element text content. | ||
* | ||
* @param {Node | undefined} node | ||
* @protected | ||
* @override | ||
*/ | ||
updateDefaultNode(node) { | ||
if (node) { | ||
node.textContent = this.widgetTitle; | ||
} | ||
|
||
// Notify the host after update. | ||
super.updateDefaultNode(node); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { expect } from '@vaadin/chai-plugins'; | ||
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers'; | ||
import '../vaadin-dashboard-widget.js'; | ||
import type { DashboardWidget } from '../vaadin-dashboard-widget.js'; | ||
|
||
describe('dashboard widget', () => { | ||
let widget: DashboardWidget; | ||
|
||
beforeEach(async () => { | ||
widget = fixtureSync(`<vaadin-dashboard-widget>Widget content</vaadin-dashboard-widget>`); | ||
await nextFrame(); | ||
}); | ||
|
||
it('should not display when hidden', () => { | ||
expect(widget.offsetHeight).to.be.above(0); | ||
widget.hidden = true; | ||
expect(widget.offsetHeight).to.eql(0); | ||
}); | ||
|
||
describe('a11y', () => { | ||
it('should have role="article"', () => { | ||
expect(widget.getAttribute('role')).to.eql('article'); | ||
}); | ||
|
||
it('should not override custom role', async () => { | ||
widget = fixtureSync(`<vaadin-dashboard-widget role="region"></vaadin-dashboard-widget>`); | ||
await nextFrame(); | ||
expect(widget.getAttribute('role')).to.eql('region'); | ||
}); | ||
|
||
it('should add title id to aria-labelledby attribute when using property', async () => { | ||
widget.widgetTitle = 'Custom title'; | ||
await nextFrame(); | ||
const title = widget.querySelector('[slot="title"]'); | ||
expect(widget.getAttribute('aria-labelledby')).equal(title?.id); | ||
}); | ||
|
||
it('should add title id to aria-labelledby attribute when using slot', async () => { | ||
const title = document.createElement('div'); | ||
title.id = 'custom-title'; | ||
title.slot = 'title'; | ||
title.textContent = 'Custom title'; | ||
widget.appendChild(title); | ||
|
||
await nextFrame(); | ||
expect(widget.getAttribute('aria-labelledby')).equal(title?.id); | ||
}); | ||
|
||
it('should have text content for the title', async () => { | ||
widget.widgetTitle = 'Custom title'; | ||
await nextFrame(); | ||
const title = widget.querySelector('[slot="title"]'); | ||
expect(title?.textContent).equal('Custom title'); | ||
}); | ||
}); | ||
|
||
describe('title', () => { | ||
it('should not override custom title element', async () => { | ||
const title = document.createElement('div'); | ||
title.id = 'custom-title'; | ||
title.slot = 'title'; | ||
title.textContent = 'Custom title'; | ||
widget.appendChild(title); | ||
await nextFrame(); | ||
|
||
widget.widgetTitle = 'New title'; | ||
await nextFrame(); | ||
|
||
const titles = widget.querySelectorAll('[slot="title"]'); | ||
expect(titles.length).to.eql(1); | ||
expect(titles[0]).to.eql(title); | ||
expect(titles[0].textContent).to.eql('Custom title'); | ||
}); | ||
|
||
it('should not throw when initialized with a custom title', async () => { | ||
expect(() => { | ||
fixtureSync(` | ||
<vaadin-dashboard-widget> | ||
<div slot="title">Custom title</div> | ||
</vaadin-dashboard-widget> | ||
`); | ||
}).not.to.throw(Error); | ||
await nextFrame(); | ||
}); | ||
|
||
it('should empty title element when cleared', async () => { | ||
widget.widgetTitle = 'New title'; | ||
await nextFrame(); | ||
|
||
widget.widgetTitle = null; | ||
await nextFrame(); | ||
|
||
const title = widget.querySelector('[slot="title"]'); | ||
expect(title?.textContent).to.eql(''); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.