Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit f8ba48f

Browse files
authored
feat(drawer): Convert JS to TypeScript (#4390)
Refs #4225
1 parent 5052ada commit f8ba48f

File tree

15 files changed

+287
-244
lines changed

15 files changed

+287
-244
lines changed

packages/mdc-dialog/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class MDCDialog extends MDCComponent<MDCDialogFoundation> {
7070
private container_!: HTMLElement; // assigned in initialize()
7171
private content_!: HTMLElement | null; // assigned in initialize()
7272
private defaultButton_!: HTMLElement | null; // assigned in initialize()
73-
private initialFocusEl_!: HTMLElement | null; // assigned in initialize()
73+
private initialFocusEl_?: HTMLElement; // assigned in initialize()
7474

7575
private focusTrap_!: createFocusTrap.FocusTrap; // assigned in initialSyncWithDOM()
7676
private focusTrapFactory_!: FocusTrapFactory; // assigned in initialize()
@@ -83,7 +83,7 @@ class MDCDialog extends MDCComponent<MDCDialogFoundation> {
8383

8484
initialize(
8585
focusTrapFactory: FocusTrapFactory = createFocusTrap as unknown as FocusTrapFactory,
86-
initialFocusEl: Element | null = null) {
86+
initialFocusEl?: HTMLElement) {
8787
const container = this.root_.querySelector<HTMLElement>(strings.CONTAINER_SELECTOR);
8888
if (!container) {
8989
throw new Error(`Dialog component requires a ${strings.CONTAINER_SELECTOR} container element`);
@@ -93,7 +93,7 @@ class MDCDialog extends MDCComponent<MDCDialogFoundation> {
9393
this.buttons_ = [].slice.call(this.root_.querySelectorAll<HTMLElement>(strings.BUTTON_SELECTOR));
9494
this.defaultButton_ = this.root_.querySelector<HTMLElement>(strings.DEFAULT_BUTTON_SELECTOR);
9595
this.focusTrapFactory_ = focusTrapFactory;
96-
this.initialFocusEl_ = initialFocusEl as HTMLElement;
96+
this.initialFocusEl_ = initialFocusEl;
9797
this.buttonRipples_ = [];
9898

9999
for (const buttonEl of this.buttons_) {

packages/mdc-dialog/util.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,24 @@
2424
import * as createFocusTrap from 'focus-trap';
2525
import {FocusTrapFactory} from './types';
2626

27-
function createFocusTrapInstance(
27+
export function createFocusTrapInstance(
2828
surfaceEl: HTMLElement,
2929
focusTrapFactory: FocusTrapFactory = createFocusTrap as unknown as FocusTrapFactory,
30-
initialFocusEl: createFocusTrap.FocusTarget | null,
30+
initialFocusEl?: createFocusTrap.FocusTarget,
3131
): createFocusTrap.FocusTrap {
32-
return focusTrapFactory(surfaceEl, ({
33-
clickOutsideDeactivates: true, // Allow handling of scrim clicks
34-
escapeDeactivates: false, // Dialog foundation handles escape key
32+
return focusTrapFactory(surfaceEl, {
33+
clickOutsideDeactivates: true, // Allow handling of scrim clicks.
34+
escapeDeactivates: false, // Foundation handles ESC key.
3535
initialFocus: initialFocusEl,
36-
} as createFocusTrap.Options));
36+
});
3737
}
3838

39-
function isScrollable(el: HTMLElement | null): boolean {
39+
export function isScrollable(el: HTMLElement | null): boolean {
4040
return el ? el.scrollHeight > el.offsetHeight : false;
4141
}
4242

43-
function areTopsMisaligned(els: HTMLElement[]): boolean {
43+
export function areTopsMisaligned(els: HTMLElement[]): boolean {
4444
const tops = new Set();
4545
[].forEach.call(els, (el: HTMLElement) => tops.add(el.offsetTop));
4646
return tops.size > 1;
4747
}
48-
49-
export {createFocusTrapInstance, isScrollable, areTopsMisaligned};

packages/mdc-drawer/adapter.js renamed to packages/mdc-drawer/adapter.ts

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,79 +21,70 @@
2121
* THE SOFTWARE.
2222
*/
2323

24-
/* eslint no-unused-vars: [2, {"args": "none"}] */
25-
2624
/**
27-
* Adapter for MDC Drawer
28-
*
29-
* Defines the shape of the adapter expected by the foundation. Implement this
30-
* adapter to integrate the Drawer into your framework. See
31-
* https://github.com/material-components/material-components-web/blob/master/docs/authoring-components.md
32-
* for more information.
33-
*
34-
* @record
25+
* Defines the shape of the adapter expected by the foundation.
26+
* Implement this adapter for your framework of choice to delegate updates to
27+
* the component in your framework of choice. See architecture documentation
28+
* for more details.
29+
* https://github.com/material-components/material-components-web/blob/master/docs/code/architecture.md
3530
*/
36-
class MDCDrawerAdapter {
31+
interface MDCDrawerAdapter {
3732
/**
3833
* Adds a class to the root Element.
39-
* @param {string} className
4034
*/
41-
addClass(className) {}
35+
addClass(className: string): void;
4236

4337
/**
4438
* Removes a class from the root Element.
45-
* @param {string} className
4639
*/
47-
removeClass(className) {}
40+
removeClass(className: string): void;
4841

4942
/**
5043
* Returns true if the root Element contains the given class.
51-
* @param {string} className
52-
* @return {boolean}
5344
*/
54-
hasClass(className) {}
45+
hasClass(className: string): boolean;
5546

5647
/**
57-
* @param {!Element} element target element to verify class name
58-
* @param {string} className class name
48+
* @param element target element to verify class name
49+
* @param className class name
5950
*/
60-
elementHasClass(element, className) {}
51+
elementHasClass(element: Element, className: string): boolean;
6152

6253
/**
6354
* Saves the focus of currently active element.
6455
*/
65-
saveFocus() {}
56+
saveFocus(): void;
6657

6758
/**
6859
* Restores focus to element previously saved with 'saveFocus'.
6960
*/
70-
restoreFocus() {}
61+
restoreFocus(): void;
7162

7263
/**
7364
* Focuses the active / selected navigation item.
7465
*/
75-
focusActiveNavigationItem() {}
66+
focusActiveNavigationItem(): void;
7667

7768
/**
7869
* Emits a custom event "MDCDrawer:closed" denoting the drawer has closed.
7970
*/
80-
notifyClose() {}
71+
notifyClose(): void;
8172

8273
/**
8374
* Emits a custom event "MDCDrawer:opened" denoting the drawer has opened.
8475
*/
85-
notifyOpen() {}
76+
notifyOpen(): void;
8677

8778
/**
8879
* Traps focus on root element and focuses the active navigation element.
8980
*/
90-
trapFocus() {}
81+
trapFocus(): void;
9182

9283
/**
9384
* Releases focus trap from root element which was set by `trapFocus`
9485
* and restores focus to where it was prior to calling `trapFocus`.
9586
*/
96-
releaseFocus() {}
87+
releaseFocus(): void;
9788
}
9889

99-
export default MDCDrawerAdapter;
90+
export {MDCDrawerAdapter as default, MDCDrawerAdapter};

packages/mdc-drawer/constants.js renamed to packages/mdc-drawer/constants.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,22 @@
2020
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
* THE SOFTWARE.
2222
*/
23-
/** @enum {string} */
23+
2424
const cssClasses = {
25-
ROOT: 'mdc-drawer',
25+
ANIMATE: 'mdc-drawer--animate',
26+
CLOSING: 'mdc-drawer--closing',
2627
DISMISSIBLE: 'mdc-drawer--dismissible',
2728
MODAL: 'mdc-drawer--modal',
2829
OPEN: 'mdc-drawer--open',
29-
ANIMATE: 'mdc-drawer--animate',
3030
OPENING: 'mdc-drawer--opening',
31-
CLOSING: 'mdc-drawer--closing',
31+
ROOT: 'mdc-drawer',
3232
};
3333

34-
/** @enum {string} */
3534
const strings = {
3635
APP_CONTENT_SELECTOR: '.mdc-drawer-app-content',
37-
SCRIM_SELECTOR: '.mdc-drawer-scrim',
3836
CLOSE_EVENT: 'MDCDrawer:closed',
3937
OPEN_EVENT: 'MDCDrawer:opened',
38+
SCRIM_SELECTOR: '.mdc-drawer-scrim',
4039
};
4140

4241
export {cssClasses, strings};

packages/mdc-drawer/dismissible/foundation.js renamed to packages/mdc-drawer/dismissible/foundation.ts

Lines changed: 49 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -21,48 +21,42 @@
2121
* THE SOFTWARE.
2222
*/
2323

24-
import MDCDrawerAdapter from '../adapter';
2524
import {MDCFoundation} from '@material/base/foundation';
25+
import {MDCDrawerAdapter} from '../adapter';
2626
import {cssClasses, strings} from '../constants';
2727

28-
/**
29-
* @extends {MDCFoundation<!MDCDrawerAdapter>}
30-
*/
31-
class MDCDismissibleDrawerFoundation extends MDCFoundation {
32-
/** @return enum {string} */
28+
class MDCDismissibleDrawerFoundation extends MDCFoundation<MDCDrawerAdapter> {
3329
static get strings() {
3430
return strings;
3531
}
3632

37-
/** @return enum {string} */
3833
static get cssClasses() {
3934
return cssClasses;
4035
}
4136

42-
static get defaultAdapter() {
43-
return /** @type {!MDCDrawerAdapter} */ ({
44-
addClass: (/* className: string */) => {},
45-
removeClass: (/* className: string */) => {},
46-
hasClass: (/* className: string */) => {},
47-
elementHasClass: (/* element: !Element, className: string */) => {},
48-
notifyClose: () => {},
49-
notifyOpen: () => {},
50-
saveFocus: () => {},
51-
restoreFocus: () => {},
52-
focusActiveNavigationItem: () => {},
53-
trapFocus: () => {},
54-
releaseFocus: () => {},
55-
});
37+
static get defaultAdapter(): MDCDrawerAdapter {
38+
// tslint:disable:object-literal-sort-keys
39+
return {
40+
addClass: () => undefined,
41+
removeClass: () => undefined,
42+
hasClass: () => false,
43+
elementHasClass: () => false,
44+
notifyClose: () => undefined,
45+
notifyOpen: () => undefined,
46+
saveFocus: () => undefined,
47+
restoreFocus: () => undefined,
48+
focusActiveNavigationItem: () => undefined,
49+
trapFocus: () => undefined,
50+
releaseFocus: () => undefined,
51+
};
52+
// tslint:enable:object-literal-sort-keys
5653
}
5754

58-
constructor(adapter) {
59-
super(Object.assign(MDCDismissibleDrawerFoundation.defaultAdapter, adapter));
60-
61-
/** @private {number} */
62-
this.animationFrame_ = 0;
55+
private animationFrame_ = 0;
56+
private animationTimer_ = 0;
6357

64-
/** @private {number} */
65-
this.animationTimer_ = 0;
58+
constructor(adapter?: Partial<MDCDrawerAdapter>) {
59+
super({...MDCDismissibleDrawerFoundation.defaultAdapter, ...adapter});
6660
}
6761

6862
destroy() {
@@ -74,9 +68,6 @@ class MDCDismissibleDrawerFoundation extends MDCFoundation {
7468
}
7569
}
7670

77-
/**
78-
* Function to open the drawer.
79-
*/
8071
open() {
8172
if (this.isOpen() || this.isOpening() || this.isClosing()) {
8273
return;
@@ -93,9 +84,6 @@ class MDCDismissibleDrawerFoundation extends MDCFoundation {
9384
this.adapter_.saveFocus();
9485
}
9586

96-
/**
97-
* Function to close the drawer.
98-
*/
9987
close() {
10088
if (!this.isOpen() || this.isOpening() || this.isClosing()) {
10189
return;
@@ -105,48 +93,31 @@ class MDCDismissibleDrawerFoundation extends MDCFoundation {
10593
}
10694

10795
/**
108-
* Extension point for when drawer finishes open animation.
109-
* @protected
96+
* @return true if drawer is in open state.
11097
*/
111-
opened() {}
112-
113-
/**
114-
* Extension point for when drawer finishes close animation.
115-
* @protected
116-
*/
117-
closed() {}
118-
119-
/**
120-
* Returns true if drawer is in open state.
121-
* @return {boolean}
122-
*/
123-
isOpen() {
98+
isOpen(): boolean {
12499
return this.adapter_.hasClass(cssClasses.OPEN);
125100
}
126101

127102
/**
128-
* Returns true if drawer is animating open.
129-
* @return {boolean}
103+
* @return true if drawer is animating open.
130104
*/
131-
isOpening() {
105+
isOpening(): boolean {
132106
return this.adapter_.hasClass(cssClasses.OPENING) || this.adapter_.hasClass(cssClasses.ANIMATE);
133107
}
134108

135109
/**
136-
* Returns true if drawer is animating closed.
137-
* @return {boolean}
110+
* @return true if drawer is animating closed.
138111
*/
139-
isClosing() {
112+
isClosing(): boolean {
140113
return this.adapter_.hasClass(cssClasses.CLOSING);
141114
}
142115

143116
/**
144117
* Keydown handler to close drawer when key is escape.
145-
* @param evt
146118
*/
147-
handleKeydown(evt) {
119+
handleKeydown(evt: KeyboardEvent) {
148120
const {keyCode, key} = evt;
149-
150121
const isEscape = key === 'Escape' || keyCode === 27;
151122
if (isEscape) {
152123
this.close();
@@ -155,14 +126,13 @@ class MDCDismissibleDrawerFoundation extends MDCFoundation {
155126

156127
/**
157128
* Handles a transition end event on the root element.
158-
* @param {!Event} evt
159129
*/
160-
handleTransitionEnd(evt) {
130+
handleTransitionEnd(evt: TransitionEvent) {
161131
const {OPENING, CLOSING, OPEN, ANIMATE, ROOT} = cssClasses;
162132

163133
// In Edge, transitionend on ripple pseudo-elements yields a target without classList, so check for Element first.
164-
const isElement = evt.target instanceof Element;
165-
if (!isElement || !this.adapter_.elementHasClass(/** @type {!Element} */ (evt.target), ROOT)) {
134+
const isRootElement = this.isElement_(evt.target) && this.adapter_.elementHasClass(evt.target, ROOT);
135+
if (!isRootElement) {
166136
return;
167137
}
168138

@@ -182,19 +152,32 @@ class MDCDismissibleDrawerFoundation extends MDCFoundation {
182152
this.adapter_.removeClass(CLOSING);
183153
}
184154

155+
/**
156+
* Extension point for when drawer finishes open animation.
157+
*/
158+
protected opened() {} // tslint:disable-line:no-empty
159+
160+
/**
161+
* Extension point for when drawer finishes close animation.
162+
*/
163+
protected closed() {} // tslint:disable-line:no-empty
164+
185165
/**
186166
* Runs the given logic on the next animation frame, using setTimeout to factor in Firefox reflow behavior.
187-
* @param {Function} callback
188-
* @private
189167
*/
190-
runNextAnimationFrame_(callback) {
168+
private runNextAnimationFrame_(callback: () => void) {
191169
cancelAnimationFrame(this.animationFrame_);
192170
this.animationFrame_ = requestAnimationFrame(() => {
193171
this.animationFrame_ = 0;
194172
clearTimeout(this.animationTimer_);
195173
this.animationTimer_ = setTimeout(callback, 0);
196174
});
197175
}
176+
177+
private isElement_(element: unknown): element is Element {
178+
// In Edge, transitionend on ripple pseudo-elements yields a target without classList.
179+
return Boolean((element as Element).classList);
180+
}
198181
}
199182

200-
export default MDCDismissibleDrawerFoundation;
183+
export {MDCDismissibleDrawerFoundation as default, MDCDismissibleDrawerFoundation};

0 commit comments

Comments
 (0)