-
Notifications
You must be signed in to change notification settings - Fork 6.8k
feat(sticky-header): Initial version of sticky header #5175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial pass
|
||
|
||
@Directive({ | ||
selector: '[md-sticky-viewport], [cdkStickyViewport], [cdkStickyRegion]', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove [md-sticky-viewport]
and [cdkStickyViewport]
.
@Directive({ | ||
selector: '[md-sticky-viewport], [cdkStickyViewport], [cdkStickyRegion]', | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove empty lines so it's clear that selector cdkStickyRegion
is associated with StickyParentDirective
}) | ||
|
||
|
||
@Injectable() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this injectable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right~ We don't need @Injectable for StickyParentDirective.
export class StickyParentDirective implements OnInit, OnDestroy, AfterViewInit { | ||
|
||
// The parent element, which with the 'md-sticky-viewport' tag | ||
private pelem: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable can be removed
} | ||
|
||
ngOnInit(): void { | ||
this.pelem.classList.add('sticky-parent'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this class? You can get the parent element by injection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed OnInit, AfterViewInit and onDestory class. Because we don't need them.
private width: string = 'auto'; | ||
|
||
constructor(private element: ElementRef, | ||
public findScroll: Scrollable, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scrollable
@@ -0,0 +1,334 @@ | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 2 space for indent
// detecting when a container's height changes | ||
let currentContainerHeight: number = this.getCssNumber(this.stickyParent, 'height'); | ||
if (currentContainerHeight !== this.containerHeight) { | ||
this.defineRestrictions(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually defineRestrictions()
are called before sticker()
. Do you still need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deleted checking currentContainerHeight in sticker(). Because we always call defineRestrictions() before sticker().
} | ||
|
||
this.defineRestrictions(); | ||
this.sticker(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combine defineRestrictions
and sticker
?
defineRestrictionsAndStick()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combined defineRestrictions() and sticker() as defineRestrictionsAndStick()
this.upperScrollableContainer.addEventListener('touchmove', this.onTouchMoveBind, false); | ||
|
||
Observable.fromEvent(this.upperScrollableContainer, 'scroll') | ||
.subscribe(() => this.onScroll()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be
Observable.fromEvent(this.upperScrollableContainer, 'scroll')
.subscribe(() => this.defineRestrictionsAndStick());
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that they're okay with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
add chose parent add support to 'optional 'cdkStickyRegion' input ' add app-demo for sticky-header fix bugs and deleted unused tag id in HTML files modify
CLAs look good, thanks! |
change some format to pass TSlint check
add '_' before private elements
delete @Injectable for StickyHeaderDirective. Because we do not need @Injectable
refine code
.firebaserc
Outdated
@@ -0,0 +1,5 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? revert this file
src/demo-app/demo-app-module.ts
Outdated
@@ -74,9 +74,11 @@ import { | |||
MdToolbarModule, | |||
MdTooltipModule, | |||
OverlayContainer, | |||
StyleModule | |||
StyleModule, | |||
MdStickyHeaderModule, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you put demo related part in #5176? You can remove that part from this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed demo code
src/lib/sticky-header/index.ts
Outdated
declarations: [StickyParentDirective, StickyHeaderDirective], | ||
exports: [StickyParentDirective, StickyHeaderDirective, MdCommonModule], | ||
}) | ||
export class MdStickyHeaderModule {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call it CdkStickyHeaderModule?
@Directive({ | ||
selector: '[cdkStickyRegion]', | ||
}) | ||
export class StickyParentDirective { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CdkStickyRegion
Add docs for this directive?
}) | ||
|
||
@Injectable() | ||
export class StickyHeaderDirective implements OnDestroy, AfterViewInit { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change the name to CdkStickyHeader?
public originalCss: any; | ||
|
||
// the height of 'stickyParent' | ||
public containerHeight: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be local
this.elem.style.position = 'fixed'; | ||
this.elem.style.top = this.getCssNumber(this.upperScrollableContainer, 'top') + 'px'; | ||
|
||
this._scrollingRight = this.upperScrollableContainer.offsetLeft + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this _scrollingRight
used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deleted _scrollingRight
private _scrollingRight: number; | ||
|
||
// the padding of 'elem' | ||
private _elementPadding: any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be a local variable
|
||
// the padding of 'elem' | ||
private _elementPadding: any; | ||
private _paddingNumber: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be a local variable
} | ||
|
||
|
||
sticker(): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add doc
encapsulate 'set style for element'
Added reference link to Modernizer in docs of getSupportList()
Deleted "_supportList" variable
renamed 'isIE' to 'isStickyPositionSupported', and removed extra space before Observable
Set debounce time as a const variable
Changed ' if(this.stickyParent == null)' to ' if(!this.stickyParent)'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments Addressed. Please take another look 👍
@Directive({ | ||
selector: '[cdkStickyHeader]', | ||
}) | ||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved docs above @directive 👍
*/ | ||
private _supportList: Array<string>; | ||
|
||
constructor(_element: ElementRef, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed the underscore in _element: ElementRef,
|
||
constructor(_element: ElementRef, | ||
scrollable: Scrollable, | ||
@Optional() public parentReg: CdkStickyRegion) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. It's short for region. Expanded~
} | ||
|
||
ngAfterViewInit(): void { | ||
if(this.isIE === true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
if(this.isIE === true) { | ||
this.stickyParent = this.parentReg != null ? | ||
this.parentReg._elementRef.nativeElement : this.element.parentElement; | ||
this.originalCss = this.generateCssStyle(this.getCssValue(this.element, 'zIndex'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added more newlines between params
|
||
attach() { | ||
this._onScrollSubscription = Observable.fromEvent(this.upperScrollableContainer, 'scroll') | ||
.debounceTime(5).subscribe(() => this.defineRestrictionsAndStick()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set debounce time as a const variable and added docs to explain why it is 5.
* when to start, when to finish) | ||
*/ | ||
defineRestrictions(): void { | ||
if(this.stickyParent == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
/** | ||
* This function is used to generate a variable which contains 7 css styles. | ||
* @param zIndex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*/ | ||
generateCssStyle(zIndex:any, position:any, top:any, right:any, | ||
left:any, bottom:any, width:any): any { | ||
let targetCSS = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
*/ | ||
generateCssStyle(zIndex:any, position:any, top:any, right:any, | ||
left:any, bottom:any, width:any): any { | ||
let targetCSS = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returned targetCSS;
*/ | ||
setStrategyAccordingToCompatibility(): void { | ||
let supportList = this.getSupportList(); | ||
if(supportList.length == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add space between if
and (
. Use ===
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
let supportList = this.getSupportList(); | ||
if(supportList.length == 0) { | ||
this.isStickyPositionSupported = true; | ||
}else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add space between }
and else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
let supportList: Array<string> = new Array<string>(); | ||
let stickyText = ''; | ||
for (let i = 0; i < prefixTestList.length; i++ ) { | ||
stickyText += 'position:' + prefixTestList[i] + 'sticky;'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need +=
here? Add comments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope~ Do not need +=
, should use =
.
private _onResizeBind: EventListener = this.onResize.bind(this); | ||
private _onTouchMoveBind: EventListener = this.onTouchMove.bind(this); | ||
isStuck: boolean = false; | ||
isStickyPositionSupported: boolean = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add docs about this variable.
Is true
means position: sticky
supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added docs for isStickyPositionSupported
variable
if(supportList.length == 0) { | ||
this.isStickyPositionSupported = true; | ||
}else { | ||
let prefix: string = supportList[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only need supportList[0]
? Add comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Because supportList
contains all the prefix that can make sticky positioning work in the current browser. We only need to get one prefix and make position: prefix + 'sticky'
, then sticky position will work.
Added comments
Comments Addressed. 👍 |
declarations: [CdkStickyRegion, CdkStickyHeader], | ||
exports: [CdkStickyRegion, CdkStickyHeader, MdCommonModule], | ||
}) | ||
export class StickyHeaderModule {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticed that all this code is in src/lib
. As part of the cdk, it should all be under src/cdk
. You could do this in a another PR after this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} | ||
|
||
|
||
// STICK_START_CLASS is used to mark a header is stuck. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** Class applied when the header is "stuck" */
/** Class applied when the header is not "stuck" */
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* or 'position: -webkit-sticky'. | ||
* isStickyPositionSupported == false, means current browser does not support sticky | ||
* positioning and need to use the original implementation to get the sticky effect. | ||
* @type {boolean} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Omit type from JsDoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* isStickyPositionSupported == true, means current browser support 'position: sticky' | ||
* or 'position: -webkit-sticky'. | ||
* isStickyPositionSupported == false, means current browser does not support sticky | ||
* positioning and need to use the original implementation to get the sticky effect. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole comment can be shortened to
Whether the browser support CSS sticky positioning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
import {Subscription} from 'rxjs/Subscription'; | ||
import 'rxjs/add/observable/fromEvent'; | ||
import 'rxjs/add/operator/debounceTime'; | ||
import {createElement} from "@angular/core/src/view/element"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deep imports into @angular/core
are not allowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import {createElement} from "@angular/core/src/view/element";
I found that this import is actually unused. I just deleted it~
* (https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/positionsticky.js). | ||
*/ | ||
getSupportList(): Array<string> { | ||
let prefixTestList = ['', '-webkit-', '-ms-', '-moz-', '-o-']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just create a CSS class that has all of these applied and use that in the support check?
Also, I don't think moz
and ms
are necessary. Do you have a resource for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can not add css class. Because sticky-header
is a @Directive
instead of a @Component
. So we can not be able to apply styleURLs: xxx.css
on it. So I just directly changed it's css style in code.
let body = document.body; | ||
div.style.cssText = 'display:none;' + stickyText; | ||
body.appendChild(div); | ||
let isSupport = /sticky/i.test(window.getComputedStyle(div).position); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should ensure that this call to getComputedStyle
happens at the same time as other getComputedStyle
calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we found that the current browser support sticky positioning. The original implementation of sticky-header will not be called, which means we will not call the rest of the getComputedStyle
if the current browser support sticky positioning.
The rest getComputedStyle
will only be called when the in-build sticky positioning is not supported.
* The implementation references the compatibility checking in Modernizer | ||
* (https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/positionsticky.js). | ||
*/ | ||
getSupportList(): Array<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check needs to be gated on whether or not we're on the browser (and not rendering with platform-server
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added check whether we're on the browser
} | ||
|
||
onResize(): void { | ||
this.defineRestrictionsAndStick(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to unstick on resize, why call this at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I need to judge whether the current header need to be stuck. Calling defineRestrictionsAndStick()
to see the current state of the header. If the current header is stuck, we need to unstuck it and then stuck it again to reshape the sticky header. And if the current header is not stuck, we will do nothing. Just let it being scrolled up or down.
this._containerStart = containerTop.top; | ||
|
||
// the padding of the element being stuck | ||
let paddingNumber: any = Number(this.padding.slice(0, -2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parseInt
automatically ignores trailing non-numeric characters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found paddingNumber
is unecessary. Deleted this global variable.
deleted unused import
change comments
optimize comments
deleted unnecessary global variables(padding and stickyRegionHeight)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments Addressed. Please take another look. 👍
And I'll create a new PR to move all the code to 'src/cdk'
import {Subscription} from 'rxjs/Subscription'; | ||
import 'rxjs/add/observable/fromEvent'; | ||
import 'rxjs/add/operator/debounceTime'; | ||
import {createElement} from "@angular/core/src/view/element"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import {createElement} from "@angular/core/src/view/element";
I found that this import is actually unused. I just deleted it~
} | ||
|
||
|
||
// STICK_START_CLASS is used to mark a header is stuck. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* be one sticky-header in one 'cdkStickyRegion'. | ||
* If a user does not define a 'cdkStickyRegion' for a sticky-header, the direct | ||
* parent node of the sticky-header will be set as the 'cdkStickyRegion'. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* isStickyPositionSupported == true, means current browser support 'position: sticky' | ||
* or 'position: -webkit-sticky'. | ||
* isStickyPositionSupported == false, means current browser does not support sticky | ||
* positioning and need to use the original implementation to get the sticky effect. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* or 'position: -webkit-sticky'. | ||
* isStickyPositionSupported == false, means current browser does not support sticky | ||
* positioning and need to use the original implementation to get the sticky effect. | ||
* @type {boolean} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* The implementation references the compatibility checking in Modernizer | ||
* (https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/positionsticky.js). | ||
*/ | ||
getSupportList(): Array<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
* (https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/positionsticky.js). | ||
*/ | ||
getSupportList(): Array<string> { | ||
let prefixTestList = ['', '-webkit-', '-ms-', '-moz-', '-o-']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can not add css class. Because sticky-header
is a @Directive
instead of a @Component
. So we can not be able to apply styleURLs: xxx.css
on it. So I just directly changed it's css style in code.
* The implementation references the compatibility checking in Modernizer | ||
* (https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/positionsticky.js). | ||
*/ | ||
getSupportList(): Array<string> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added check whether we're on the browser
let body = document.body; | ||
div.style.cssText = 'display:none;' + stickyText; | ||
body.appendChild(div); | ||
let isSupport = /sticky/i.test(window.getComputedStyle(div).position); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we found that the current browser support sticky positioning. The original implementation of sticky-header will not be called, which means we will not call the rest of the getComputedStyle
if the current browser support sticky positioning.
The rest getComputedStyle
will only be called when the in-build sticky positioning is not supported.
} | ||
|
||
onResize(): void { | ||
this.defineRestrictionsAndStick(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I need to judge whether the current header need to be stuck. Calling defineRestrictionsAndStick()
to see the current state of the header. If the current header is stuck, we need to unstuck it and then stuck it again to reshape the sticky header. And if the current header is not stuck, we will do nothing. Just let it being scrolled up or down.
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
add support to 'optional 'cdkStickyRegion' input '