✨amp-consent: Added a default loading placeholder for the consent UI#19841
✨amp-consent: Added a default loading placeholder for the consent UI#19841torch2424 merged 14 commits intoampproject:masterfrom
Conversation
| <defs> | ||
| <linearGradient id="grad"> | ||
| <stop stop-color="rgb(105, 105, 105)"></stop> | ||
| <stop offset="100%" stop-color="rgba(105, 105, 105, 0)"></stop> |
There was a problem hiding this comment.
I had to update the code to make it work on Safari correctly. You'll need to do:
stop-color="rgb(105, 105, 105) stop-opacity="0"
instead here
There was a problem hiding this comment.
Thanks! Will update now 😄
zhouyx
left a comment
There was a problem hiding this comment.
Looks good to me with a few nits. Before merging the change, please make sure to sync with @spacedino and show them the demo on several real devices.
| placeholder: 'i-amphtml-consent-placeholder', | ||
| loading: 'i-amphtml-consent-ui-loading', | ||
| fill: 'i-amphtml-consent-ui-fill', | ||
| loadingPlaceholder: 'i-amphtml-consent-ui-loading-placeholder', |
There was a problem hiding this comment.
Nit: Well, placeholder by default means loading placeholder to me. Can we name it placeholder: i-amphtml-consent-ui-placeholder instead : ) A shorter name
| classList.add(consentUiClasses.placeholder); | ||
| classList.add(consentUiClasses.loadingPlaceholder); | ||
|
|
||
| const loadingSpinner = htmlFor(placeholder)` |
There was a problem hiding this comment.
nit: Is it possible to declare the string as a const at the top of the file?
There was a problem hiding this comment.
I believe @kristoferbaxter was looking into doing a compilation pass to do this, so it may not be worth worrying about.
There was a problem hiding this comment.
Yeah I originally had it as a const at the top of the file, but from what @kristoferbaxter showed me, it appeared to be using the htmlFor keyword in order to find the template strings to then be optimized. Thus I did it this way to help with that.
Though I may be wrong, we will see what Kris says 😄
There was a problem hiding this comment.
Since this htmlFor usage is within a method, it will be hoisted automatically in the single pass build. Makes the most sense within source code to place it where it is easiest to understand.
Please note: This optimization is only true in the single-pass build.
There was a problem hiding this comment.
Awesome! Thanks!
So I tried hoisting this to the top of the file, and the linter then throws syntax errors. Also, tried binding it with ${placeholderHtml}, but the template can't take in variables. I think we may need to do some additional work to allow the codebase to handle this.
Doing a quick project search, seems htmlFor() always has the template immediately after it.
|
|
||
| amp-consent.i-amphtml-consent-loading { | ||
| /* TODO: Finalize the placeholder design */ | ||
| @keyframes loading-placeholder-spin { |
There was a problem hiding this comment.
maybe prefix with amp-consent into the name of this, since keyframe names are global
| // Pop onto the back of the event queue, | ||
| // so we expect() once our mutate element in show() resolves | ||
| return mockInstance.mutateElement(() => {}).then(() => { | ||
| expect(placeholder.hasAttribute('hidden')).to.not.be.ok; |
There was a problem hiding this comment.
how about expect(placeholder.hidden).to.be.false?
| // so we expect() once our mutate element in show() resolves | ||
| return mockInstance.mutateElement(() => {}).then(() => { | ||
| expect(placeholder.hasAttribute('hidden')).to.not.be.ok; | ||
| expect(placeholder.childNodes.length).to.be.above(0); |
There was a problem hiding this comment.
try expect(placeholder.childNodes).to.not.be.empty
| // TODO(@zhouyx): Allow publishers to provide placeholder upon request | ||
| const placeholder = this.parent_.ownerDocument.createElement('placeholder'); | ||
| toggle(placeholder, false); | ||
| const {classList} = placeholder; |
There was a problem hiding this comment.
And can remove this now.
| const {classList} = placeholder; |
| const {classList} = placeholder; | ||
| classList.add(consentUiClasses.fill); | ||
| classList.add(consentUiClasses.placeholder); | ||
| classList.add(consentUiClasses.loadingPlaceholder); |
There was a problem hiding this comment.
Since you're only adding a single class to the classList, you can remove the line above and just call directly.
| classList.add(consentUiClasses.loadingPlaceholder); | |
| placeholder.classList.add(consentUiClasses.loadingPlaceholder); |
| </linearGradient> | ||
| </defs> | ||
| <path d="M11,4.4 A18,18, 0,1,0, 38,20" stroke="url(#grad)"></path> | ||
| </svg>`; |
There was a problem hiding this comment.
If we're using this definition in multiple places, it also might be a good idea to store it externally and import into this file.
There was a problem hiding this comment.
As of now, we are only thinking of using this here. Was asking @sparhami about this in the past, if we had a system in place for re-used html elements, and it appears that we do not. So we should probably do that as well if we continue to add more HTML literals.
kristoferbaxter
left a comment
There was a problem hiding this comment.
Left some details about htmlFor and a change for the classList usage.
|
@sparhami @zhouyx @kristoferbaxter Replied to comments / Made requested changes 😄 |
| insertAfterOrAtStart(this.parent_, dev().assertElement(this.ui_), null); | ||
| return this.iframeReady_.promise; | ||
|
|
||
| return this.baseInstance_.mutateElement(() => { |
There was a problem hiding this comment.
I think this would be a bit more natural as:
return Promise.all([
this.iframeReady_.promise,
this.baseInstance_.mutateElement(() => {
toggle(dev().assertElement(this.placeholder_), true);
}),
]);Its not really a performance difference in this case, but seems to more clearly communicate that the two async things are independent.
| */ | ||
| createPlaceholder_() { | ||
| // TODO(@zhouyx): Allow publishers to provide placeholder upon request | ||
| const placeholder = this.parent_.ownerDocument.createElement('placeholder'); |
There was a problem hiding this comment.
I'm not sure if it is too late to change this, but you shouldn't use a tag name like placeholder. A browser could add one with certain semantics that might be a problem. You should only ever use valid html tag names or include a dash in the name.
There was a problem hiding this comment.
I agree we should change this.
However, @zhouyx do you see any problem in changing this? Is there more code already in place around this idea?
| }); | ||
|
|
||
| describe('placeholder', () => { | ||
| it('should add a placeholder element' + |
There was a problem hiding this comment.
Having placeholder here feels a bit redundant. The test will read as "consent-ui placeholder should add a placeholder element while loading CMP Iframe". Consider something like "consent-ui placeholder should be present while loading CMP Iframe".
|
|
||
| const placeholder = consentUI.placeholder_; | ||
| expect(placeholder).to.be.ok; | ||
| expect(placeholder.hasAttribute('hidden')).to.be.ok; |
There was a problem hiding this comment.
expect(placeholder.hidden).to.be.true;
|
|
||
| // Pop onto the back of the event queue, | ||
| // so we expect() once our mutate element in show() resolves | ||
| return mockInstance.mutateElement(() => {}).then(() => { |
There was a problem hiding this comment.
Would be better to write this as an async test. Since it is just a test, no need to worry about the code generated to transform async/await into promises. That is:
should('...', async () => {
...
await mockInstance.mutateElement(() => {});
expect(...);
});…p-consent-loading-placeholder
|
@sparhami @zhouyx @kristoferbaxter Replied to comments / Made requested changes 😄 |
|
Thanks for the approval @sparhami ! Going to wait for a design approval from @spacedino and then pull this in (for anyone wondering) |
|
Had the design review, Loading Placeholder and transition were approved. With some last design changes to be implemented documented here: #19969 Merging... |
…mpproject#19841) * Added the loading placeholder html * Added the svg, and renamed some classes for consistency * Finished styles for the placeholder spinner * Need to stop the height flash/jump thing * Finished up the loading placeholder * Started tests, used htmlFor * Added tests for placeholder * Fixed precommit checks * Added fix for safari on svg * Another safari fix for svg * Made all requested changes * Made requested changes * Made all requested changes
…mpproject#19841) * Added the loading placeholder html * Added the svg, and renamed some classes for consistency * Finished styles for the placeholder spinner * Need to stop the height flash/jump thing * Finished up the loading placeholder * Started tests, used htmlFor * Added tests for placeholder * Fixed precommit checks * Added fix for safari on svg * Another safari fix for svg * Made all requested changes * Made requested changes * Made all requested changes
relates to #18828
This adds a loading spinner provided by @sparhami , and available as a jsbin: https://jsbin.com/yerevoz/1/edit?html,output
Simply adds this svg and styling whenever a loading placeholder is not provided. Note: This placeholder is 30px x 30px as that is the only default height we can guarantee for the amp consent footer thing. Any ideas on how to size the placeholder would be appreciated 😄 👍