diff --git a/package.json b/package.json index d7b06d3..f82b8a5 100644 --- a/package.json +++ b/package.json @@ -56,10 +56,11 @@ }, "dependencies": { "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-themable-mixin": "^1.6.1", + "@vaadin/vaadin-avatar": "2.0.0-alpha1", + "@vaadin/vaadin-element-mixin": "^2.4.1", "@vaadin/vaadin-lumo-styles": "^1.6.1", "@vaadin/vaadin-material-styles": "^1.3.2", - "@vaadin/vaadin-element-mixin": "^2.4.1" + "@vaadin/vaadin-themable-mixin": "^1.6.1" }, "devDependencies": { "@esm-bundle/chai": "^4.1.5", diff --git a/screenshot.png b/screenshot.png index 274ac78..71ab865 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/src/vaadin-message.d.ts b/src/vaadin-message.d.ts index 10da1b1..6287b0e 100644 --- a/src/vaadin-message.d.ts +++ b/src/vaadin-message.d.ts @@ -6,8 +6,9 @@ import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin. * `` is a Web Component for showing a single message with an author, message and time. * * ```html - * - * + * There is no real ending. It's + * just the place where you stop the story. * ``` * * ### Styling @@ -17,21 +18,12 @@ import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin. * Part name | Description * ----------|---------------- * `avatar` | The author's avatar + * `name` | Author's name + * `time` | When the message was posted + * `content` | The message itself as a slotted content * * See [ThemableMixin – how to apply styles for shadow parts](https://github.com/vaadin/vaadin-themable-mixin/wiki) * - * The following custom properties are available: - * - * Custom property | Description | Default - *---------------------------|------------------------------------------|------------- - * `--vaadin-message-value` | value of the component (between 0 and 1) | 0 - * - * The following state attributes are available for styling: - * - * Attribute | Description | Part name - * ----------------|------------------|------------ - * `myattribute` | Set an attribute | :host - * * @extends HTMLElement * @mixes ThemableMixin * @mixes ElementMixin diff --git a/src/vaadin-message.js b/src/vaadin-message.js index e9be5e6..4e274b6 100644 --- a/src/vaadin-message.js +++ b/src/vaadin-message.js @@ -6,13 +6,14 @@ import { PolymerElement, html } from '@polymer/polymer/polymer-element.js'; import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js'; import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin.js'; - +import '@vaadin/vaadin-avatar/src/vaadin-avatar.js'; /** * `` is a Web Component for showing a single message with an author, message and time. * * ```html - * - * + * There is no real ending. It's + * just the place where you stop the story. * ``` * * ### Styling @@ -22,21 +23,12 @@ import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin. * Part name | Description * ----------|---------------- * `avatar` | The author's avatar + * `name` | Author's name + * `time` | When the message was posted + * `content` | The message itself as a slotted content * * See [ThemableMixin – how to apply styles for shadow parts](https://github.com/vaadin/vaadin-themable-mixin/wiki) * - * The following custom properties are available: - * - * Custom property | Description | Default - *---------------------------|------------------------------------------|------------- - * `--vaadin-message-value` | value of the component (between 0 and 1) | 0 - * - * The following state attributes are available for styling: - * - * Attribute | Description | Part name - * ----------------|------------------|------------ - * `myattribute` | Set an attribute | :host - * * @extends HTMLElement * @mixes ThemableMixin * @mixes ElementMixin @@ -45,11 +37,27 @@ class MessageElement extends ElementMixin(ThemableMixin(PolymerElement)) { static get properties() { return { /** - * Current text value. + * Time of sending the message. It is rendered as-is to the part='time' slot, + * so the formatting is up to you. */ - value: { + time: { type: String, reflectToAttribute: true + }, + /** + * A user object that can be used to render avatar and name. + * The user object can consist of the following properties: + * ```js + * user: { + * name: string, + * abbr: string, + * img: string, + * colorIndex: number + * } + * ``` + */ + user: { + type: Object } }; } @@ -58,34 +66,52 @@ class MessageElement extends ElementMixin(ThemableMixin(PolymerElement)) { return html` -
-
[[value]]
+ [part='name'] { + flex: 1; + } + + +
+
+
[[user.name]]
+
[[time]]
+
+
+ +
`; } ready() { super.ready(); - this.setAttribute('value', 'hello world'); } static get is() { diff --git a/test/message.test.js b/test/message.test.js index 323d9d0..a2a3a9f 100644 --- a/test/message.test.js +++ b/test/message.test.js @@ -3,23 +3,68 @@ import { fixtureSync } from '@open-wc/testing-helpers'; import '../vaadin-message.js'; describe('message', () => { - let message, value; + let message, avatar, content, time, name, user; beforeEach(() => { - message = fixtureSync(''); - value = message.shadowRoot.querySelector('[part="value"]'); + let root = document.documentElement; + root.style.setProperty('--vaadin-user-color-2', 'blue'); + + message = fixtureSync('Hello'); + avatar = message.shadowRoot.querySelector('vaadin-avatar'); + name = message.shadowRoot.querySelector('[part="name"]'); + content = message.shadowRoot.querySelector('[part="content"]'); + time = message.shadowRoot.querySelector('[part="time"]'); + user = { + name: 'Joan Doe', + abbr: 'JD', + img: '/test/visual/avatars/avatar.jpg', + colorIndex: 2 + }; }); it('should have a valid version number', () => { expect(message.constructor.version).to.match(/^(\d+\.)?(\d+\.)?(\d+)(-(alpha|beta)\d+)?$/); }); - it('should say initially hello world', () => { - expect(value.textContent).to.be.equal('hello world'); + it('avatar should be initially visible but without data', () => { + expect(avatar.getAttribute('name')).to.be.null; + expect(avatar.getAttribute('abbr')).to.be.null; + expect(avatar.getAttribute('img')).to.be.null; + expect(avatar.getAttribute('title')).to.be.equal('anonymous'); + expect(avatar.getAttribute('has-color-index')).to.be.null; + }); + + it('name should be initially empty', () => { + expect(name.textContent.trim()).to.be.equal(''); + }); + + it('time should be initially empty', () => { + expect(time.textContent.trim()).to.be.equal(''); + }); + + it('avatar should be set with provided user', () => { + message.user = user; + expect(avatar.getAttribute('name')).to.be.equal('Joan Doe'); + expect(avatar.getAttribute('abbr')).to.be.equal('JD'); + expect(avatar.getAttribute('img')).to.be.equal('/test/visual/avatars/avatar.jpg'); + expect(avatar.getAttribute('title')).to.be.equal('Joan Doe (JD)'); + expect(avatar.getAttribute('has-color-index')).to.be.not.null; + expect(avatar.colorIndex).to.be.equal(2); + }); + + it('name should be set with provided user', () => { + message.user = user; + expect(name.textContent).to.be.equal('Joan Doe'); + }); + + it('time should be set', () => { + message.time = 'long ago'; + expect(time.textContent).to.be.equal('long ago'); }); - it('should say hello tests', () => { - message.value = 'hello tests'; - expect(value.textContent).to.be.equal('hello tests'); + it('content should be set', () => { + const slot = content.querySelector('slot'); + const nodes = slot.assignedNodes({ flatten: true }); + expect(nodes[0].textContent).to.be.equal('Hello'); }); }); diff --git a/test/visual/avatars/avatar.jpg b/test/visual/avatars/avatar.jpg new file mode 100644 index 0000000..500862b Binary files /dev/null and b/test/visual/avatars/avatar.jpg differ diff --git a/test/visual/avatars/avatar2.jpg b/test/visual/avatars/avatar2.jpg new file mode 100644 index 0000000..9ca2e02 Binary files /dev/null and b/test/visual/avatars/avatar2.jpg differ diff --git a/test/visual/default.html b/test/visual/default.html index 304cd46..c3fc76a 100644 --- a/test/visual/default.html +++ b/test/visual/default.html @@ -6,11 +6,29 @@ +
- + There is no real + ending. It's + just the place where you stop the story. + People who succeed + have + momentum. The more they succeed, the more they want to succeed and the more they find a way to succeed. Similarly, + when someone is failing, the tendency is to get on a downward spiral that can even become a self-fulfilling + prophecy. + + There is no real ending. It's + just the place where you stop the story.