-
Notifications
You must be signed in to change notification settings - Fork 6
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
fix(side-drawer): refactor side drawer #1022
Merged
Merged
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
ff7c09e
Refactor to place constants closer to context
YonatanKra 9fabd36
Refactor events tests to reflect their true actions
YonatanKra 24c56ad
Test the show an hide methods
YonatanKra 6105147
Change close to hide
YonatanKra 3c6b1b1
Prettier
YonatanKra 9c5beda
Remove console.log
YonatanKra d597a8c
Remove comments from non API functions
YonatanKra 926db3e
Delete openChanged method
YonatanKra 7238855
Make event handlers private
YonatanKra 31e7e02
Effectively remove the listener
YonatanKra 4b9a290
Test keypress
YonatanKra bd61f82
Prettier
YonatanKra 0b7d2cc
Remove the observer and the empty constructor
YonatanKra 60fa634
Added missing "addElement"
YonatanKra f294e3a
Merge branch 'master' into refactor-side-drawer
YonatanKra b13328d
Refactor tests a bit
YonatanKra c6c6a99
Merge branch 'refactor-side-drawer' of https://github.com/Vonage/vivi…
YonatanKra 0cab233
Oopsy submitting `only` in tests
YonatanKra 79030f6
Add onKeydown to scrim
rinaok File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ import { | |
} from 'lit-element'; | ||
import { ifDefined } from 'lit-html/directives/if-defined'; | ||
import { classMap } from 'lit-html/directives/class-map'; | ||
import { observer } from '@material/mwc-base/observer'; | ||
import { DocumentWithBlockingElements } from 'blocking-elements'; | ||
|
||
const blockingElements = | ||
|
@@ -18,64 +17,51 @@ export class VWCSideDrawerBase extends LitElement { | |
* accepts boolean value | ||
* @public | ||
* */ | ||
@property({ type: Boolean, reflect: true }) | ||
@property({ | ||
type: Boolean, | ||
reflect: true | ||
}) | ||
alternate = false; | ||
|
||
/** | ||
* @prop hasTopBar - adds top bar to the side drawer | ||
* accepts boolean value | ||
* @public | ||
* */ | ||
@property({ type: Boolean, reflect: true }) | ||
@property({ | ||
type: Boolean, | ||
reflect: true | ||
}) | ||
hasTopBar?: boolean; | ||
|
||
/** | ||
* @prop type - can be modal, dismissible or empty | ||
* accepts String value | ||
* @public | ||
* */ | ||
@property({ type: String, reflect: true }) | ||
@property({ | ||
type: String, | ||
reflect: true | ||
}) | ||
type = ''; | ||
|
||
/** | ||
* @prop absolute - the modal can be fixed or absolute | ||
* accepts Boolean value | ||
* @public | ||
* */ | ||
@property({ type: Boolean, reflect: true }) | ||
@property({ | ||
type: Boolean, | ||
reflect: true | ||
}) | ||
absolute = false; | ||
|
||
@property({ type: Boolean, reflect: true }) | ||
@observer(function ( | ||
this: VWCSideDrawerBase, | ||
isOpen: boolean, | ||
wasOpen: boolean | ||
) { | ||
if (isOpen) { | ||
this.show(); | ||
// wasOpen helps with first render (when it is `undefined`) perf | ||
} else if (wasOpen !== undefined) { | ||
this.close(); | ||
} | ||
this.openChanged(isOpen); | ||
@property({ | ||
type: Boolean, | ||
reflect: true | ||
}) | ||
open = false; | ||
/** | ||
* Invoked when the element open state is updated. | ||
* | ||
* Expressions inside this method will trigger upon open state change. | ||
* | ||
* @param _isOpen Boolean of open state | ||
*/ openChanged( | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
_isOpen: boolean | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
): void {} | ||
|
||
constructor() { | ||
super(); | ||
this.addEventListener('transitionend', () => this.onTransitionEnd()); | ||
} | ||
/** | ||
* Opens the side drawer from the closed state. | ||
* @public | ||
|
@@ -88,175 +74,130 @@ export class VWCSideDrawerBase extends LitElement { | |
* Closes the side drawer from the open state. | ||
* @public | ||
*/ | ||
close(): void { | ||
hide(): void { | ||
this.open = false; | ||
} | ||
|
||
/** | ||
* Side drawer finished open animation. | ||
*/ | ||
#opened(): void { | ||
this.#trapFocus(); | ||
this.#notifyOpen(); | ||
connectedCallback() { | ||
super.connectedCallback(); | ||
this.addEventListener('transitionend', this.#onTransitionEnd); | ||
this.addEventListener('keydown', this.#onKeydown); | ||
} | ||
|
||
/** | ||
* Side drawer finished close animation. | ||
*/ | ||
#closed(): void { | ||
disconnectedCallback(): void { | ||
super.disconnectedCallback(); | ||
this.#releaseFocus(); | ||
this.#notifyClose(); | ||
this.removeEventListener('transitionend', this.#onTransitionEnd); | ||
this.removeEventListener('keydown', this.#onKeydown); | ||
} | ||
|
||
/** | ||
* DispatchEvent creator. | ||
* @param eventName | ||
*/ | ||
#createDispatchEvent(eventName: string) { | ||
const init: CustomEventInit = { bubbles: true, composed: true }; | ||
const ev = new CustomEvent(eventName, init); | ||
this.dispatchEvent(ev); | ||
} | ||
protected render(): TemplateResult { | ||
const dismissible = this.type === 'dismissible' || this.type === 'modal'; | ||
const modal = this.type === 'modal'; | ||
const topBar = this.hasTopBar ? this.renderTopBar() : ''; | ||
const scrim = this.type === 'modal' && this.open ? this.renderScrim() : ''; | ||
const alternate = this.alternate ? 'vvd-scheme-alternate' : undefined; | ||
const absolute = this.type === 'modal' && this.absolute; | ||
|
||
/** | ||
* Notify close. | ||
* | ||
* @fires SideDrawer#closed | ||
*/ | ||
#notifyClose(): void { | ||
this.#createDispatchEvent('closed'); | ||
} | ||
const classes = { | ||
'vvd-side-drawer--alternate': this.alternate, | ||
'vvd-side-drawer--dismissible': dismissible, | ||
'vvd-side-drawer--modal': modal, | ||
'vvd-side-drawer--open': this.open, | ||
'vvd-side-drawer--absolute': absolute, | ||
}; | ||
|
||
/** | ||
* Notify open. | ||
* | ||
* @fires SideDrawer#opened | ||
*/ | ||
#notifyOpen(): void { | ||
this.#createDispatchEvent('opened'); | ||
} | ||
return html` | ||
<aside | ||
part="${ifDefined(alternate)}" | ||
class="side-drawer ${classMap(classes)}" | ||
> | ||
${topBar} | ||
|
||
disconnectedCallback(): void { | ||
super.disconnectedCallback(); | ||
this.#releaseFocus(); | ||
this.removeEventListener('transitionend', () => this.onTransitionEnd()); | ||
<div class="vvd-side-drawer--content"> | ||
<slot></slot> | ||
</div> | ||
</aside> | ||
|
||
${scrim} | ||
`; | ||
} | ||
|
||
/** | ||
* Traps focus on root element and focuses the active navigation element. | ||
* | ||
* Notify trap focus. | ||
* @fires SideDrawer#trapFocus | ||
*/ | ||
#trapFocus(): void { | ||
blockingElements.push(this); | ||
this.#createDispatchEvent('trapFocus'); | ||
private renderTopBar(): TemplateResult { | ||
return html` | ||
<div class="vvd-side-drawer--top-bar"> | ||
<slot name="top-bar"></slot> | ||
</div>`; | ||
} | ||
|
||
/** | ||
* Releases focus trap from root element which was set by `trapFocus`. | ||
* | ||
* Notify release focus. | ||
* @fires SideDrawer#releaseFocus | ||
*/ | ||
#releaseFocus(): void { | ||
blockingElements.remove(this); | ||
this.#createDispatchEvent('releaseFocus'); | ||
private renderScrim(): TemplateResult { | ||
return html` | ||
<div | ||
class="vvd-side-drawer--scrim ${this.absolute | ||
? 'vvd-side-drawer--absolute' | ||
: ''}" | ||
@click="${this.#handleScrimClick}" | ||
></div>`; | ||
} | ||
|
||
/** | ||
* Click handler to close side drawer when scrim is clicked. | ||
*/ | ||
handleScrimClick(): void { | ||
#handleScrimClick(): void { | ||
if (this.type === 'modal' && this.open) { | ||
this.close(); | ||
this.hide(); | ||
} | ||
} | ||
|
||
/** | ||
* Keydown handler to close side drawer when key is escape. | ||
*/ | ||
onKeydown({ key }: KeyboardEvent): void { | ||
console.log(this.type, this.open, key); | ||
#onKeydown = ({ key }: KeyboardEvent): void => { | ||
if (this.type === 'modal' && this.open && key === 'Escape') { | ||
this.close(); | ||
this.hide(); | ||
} | ||
} | ||
}; | ||
|
||
/** | ||
* Handles the `transitionend` event when the side drawer finishes opening/closing. | ||
*/ | ||
onTransitionEnd(): void { | ||
#onTransitionEnd = (): void => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should consider changing the name to #handleTransitionEnd |
||
if (this.type === 'modal') { | ||
// when side drawer finishes open animation | ||
if (this.open) { | ||
this.#opened(); | ||
} else { | ||
// when side drawer finishes close animation | ||
// when side drawer finishes hide animation | ||
this.#closed(); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
/** | ||
* renderTopBar | ||
* @slot top-bar | ||
* @returns TemplateResult | ||
*/ | ||
private renderTopBar(): TemplateResult { | ||
return html`<div class="vvd-side-drawer--top-bar"> | ||
<slot name="top-bar"></slot> | ||
</div>`; | ||
#opened(): void { | ||
this.#trapFocus(); | ||
this.#notifyOpen(); | ||
} | ||
|
||
/** | ||
* renderScrim | ||
* @returns TemplateResult | ||
*/ | ||
private renderScrim(): TemplateResult { | ||
// eslint-disable-next-line lit-a11y/click-events-have-key-events | ||
return html`<div | ||
class="vvd-side-drawer--scrim ${this.absolute | ||
? 'vvd-side-drawer--absolute' | ||
: ''}" | ||
@click="${this.handleScrimClick}" | ||
></div>`; | ||
#closed(): void { | ||
this.#releaseFocus(); | ||
this.#notifyClose(); | ||
} | ||
|
||
/** | ||
* the html markup | ||
* @internal | ||
* */ | ||
protected render(): TemplateResult { | ||
const dismissible = this.type === 'dismissible' || this.type === 'modal'; | ||
const modal = this.type === 'modal'; | ||
const topBar = this.hasTopBar ? this.renderTopBar() : ''; | ||
const scrim = this.type === 'modal' && this.open ? this.renderScrim() : ''; | ||
const alternate = this.alternate ? 'vvd-scheme-alternate' : undefined; | ||
const absolute = this.type === 'modal' && this.absolute; | ||
|
||
const classes = { | ||
'vvd-side-drawer--alternate': this.alternate, | ||
'vvd-side-drawer--dismissible': dismissible, | ||
'vvd-side-drawer--modal': modal, | ||
'vvd-side-drawer--open': this.open, | ||
'vvd-side-drawer--absolute': absolute, | ||
#createDispatchEvent(eventName: string) { | ||
const init: CustomEventInit = { | ||
bubbles: true, | ||
composed: true | ||
}; | ||
const ev = new CustomEvent(eventName, init); | ||
this.dispatchEvent(ev); | ||
} | ||
|
||
return html` | ||
<aside | ||
part="${ifDefined(alternate)}" | ||
class="side-drawer ${classMap(classes)}" | ||
@keydown=${this.onKeydown} | ||
> | ||
${topBar} | ||
#notifyClose(): void { | ||
this.#createDispatchEvent('closed'); | ||
} | ||
|
||
<div class="vvd-side-drawer--content"> | ||
<slot></slot> | ||
</div> | ||
</aside> | ||
#notifyOpen(): void { | ||
this.#createDispatchEvent('opened'); | ||
} | ||
|
||
${scrim} | ||
`; | ||
#trapFocus(): void { | ||
blockingElements.push(this); | ||
this.#createDispatchEvent('trapFocus'); | ||
} | ||
|
||
#releaseFocus(): void { | ||
blockingElements.remove(this); | ||
this.#createDispatchEvent('releaseFocus'); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Should consider changing the name to #handleKeydown