Repository: mlaursen/react-md
Pull request #606 (2017-11-02 09:25:07)

Export the Component from typescript definition files
When using refs (e.g. on TextField), the Component type is the
type of the reference. In order to be able to run methods on
the referenced component, the type must be exported.

```
import TextField, { TextFieldComponent } from 'react-md/lib/TextFields';

// ...

  <TextField ref={(ref: TextFieldComponent) => ref.focus()} />
```

If the component type is not exported, it's not possible to call
methods in a typesafe manner.


Patch:
diff --git a/docs/src/client/registerServiceWorker.js b/docs/src/client/registerServiceWorker.js
index 7d77633ce9..b4670ee11c 100644
--- a/docs/src/client/registerServiceWorker.js
+++ b/docs/src/client/registerServiceWorker.js
@@ -65,11 +65,3 @@ export default function register(store) {
     });
   }
 }
-
-export function unregister() {
-  if ('serviceWorker' in navigator) {
-    navigator.serviceWorker.ready.then((registration) => {
-      registration.unregister();
-    });
-  }
-}
diff --git a/src/js/Buttons/Button.d.ts b/src/js/Buttons/Button.d.ts
index 8d61999908..5ecf341ec0 100644
--- a/src/js/Buttons/Button.d.ts
+++ b/src/js/Buttons/Button.d.ts
@@ -43,7 +43,7 @@ export interface ButtonProps extends Props, SharedButtonProps, InjectedTooltipPr
   fixedPosition?: FixedPositions;
 }
 
-interface ButtonComponent extends React.ComponentClass<ButtonProps> {
+export interface ButtonComponent extends React.ComponentClass<ButtonProps> {
   createInk(pageX?: number, pageY?: number): void;
   focus(): void;
   getComposedComponent(): TooltippedComponent;
diff --git a/src/js/DataTables/DropdownMenuColumn.d.ts b/src/js/DataTables/DropdownMenuColumn.d.ts
index ac896af9f9..b43d44fd0e 100644
--- a/src/js/DataTables/DropdownMenuColumn.d.ts
+++ b/src/js/DataTables/DropdownMenuColumn.d.ts
@@ -11,7 +11,7 @@ export interface DropdownMenuColumnProps extends DropdownMenuProps {
   tooltipPosition?: Positions;
 }
 
-interface DropdownMenuColumnComponent extends React.ComponentClass<DropdownMenuColumnProps> {
+export interface DropdownMenuColumnComponent extends React.ComponentClass<DropdownMenuColumnProps> {
   Positions: {
     TOP_LEFT: 'tl',
     TOP_RIGHT: 'tr',
diff --git a/src/js/DataTables/MenuButtonColumn.d.ts b/src/js/DataTables/MenuButtonColumn.d.ts
index 839a23bcae..a9ea49f7bd 100644
--- a/src/js/DataTables/MenuButtonColumn.d.ts
+++ b/src/js/DataTables/MenuButtonColumn.d.ts
@@ -11,7 +11,7 @@ export interface MenuButtonColumnProps extends MenuButtonProps {
   tooltipPosition?: Positions;
 }
 
-interface MenuButtonColumnComponent extends React.ComponentClass<MenuButtonColumnProps> {
+export interface MenuButtonColumnComponent extends React.ComponentClass<MenuButtonColumnProps> {
   Positions: {
     TOP_LEFT: 'tl',
     TOP_RIGHT: 'tr',
diff --git a/src/js/DataTables/SelectFieldColumn.d.ts b/src/js/DataTables/SelectFieldColumn.d.ts
index 5fd89e6a1f..180ae8a49a 100644
--- a/src/js/DataTables/SelectFieldColumn.d.ts
+++ b/src/js/DataTables/SelectFieldColumn.d.ts
@@ -25,7 +25,7 @@ export interface SelectFieldColumnProps extends SharedSelectFieldProps, Injected
   wrapperClassName?: string;
 }
 
-interface SelectFieldColumnComponent extends React.ComponentClass<SelectFieldColumnProps> {
+export interface SelectFieldColumnComponent extends React.ComponentClass<SelectFieldColumnProps> {
   Positions: {
     TOP_LEFT: 'tl',
     TOP_RIGHT: 'tr',
diff --git a/src/js/Drawers/Drawer.d.ts b/src/js/Drawers/Drawer.d.ts
index 408c507f35..f391fef5a6 100644
--- a/src/js/Drawers/Drawer.d.ts
+++ b/src/js/Drawers/Drawer.d.ts
@@ -49,7 +49,7 @@ export interface DrawerProps extends Props {
   onVisibilityToggle?: (visible: boolean, event: React.MouseEvent<HTMLElement>) => void;
 }
 
-interface DrawerComponent extends React.ComponentClass<DrawerProps> {
+export interface DrawerComponent extends React.ComponentClass<DrawerProps> {
   DrawerTypes: {
     // Permanent drawers
     FULL_HEIGHT: 'full-height',
diff --git a/src/js/Drawers/Drawer.js b/src/js/Drawers/Drawer.js
index f3b2ee2466..c428eb7a18 100644
--- a/src/js/Drawers/Drawer.js
+++ b/src/js/Drawers/Drawer.js
@@ -219,9 +219,6 @@ export default class Drawer extends PureComponent {
      * Boolean if there should be a visible overlay when the drawer is visible. The default behavior
      * is to only include a visible overlay when the `type` is `TEMPORARY` or `TEMPORARY_MINI` and
      * the device is not a desktop.
-     *
-     * Definining this variable as `true` or `false` will override any default behavior. This means that
-     * if this is enabled for a full-height drawer, an overlay will still be created.
      */
     overlay: PropTypes.bool,
 
@@ -722,10 +719,9 @@ export default class Drawer extends PureComponent {
       }
     }
 
-    let overlayVisible = overlay;
-    if (typeof overlayVisible !== 'boolean') {
-      overlayVisible = temporary && !mini && (!desktop || clickableDesktopOverlay) && (animating || visible);
-    }
+    const overlayVisible = !mini && (!desktop || clickableDesktopOverlay)
+      && (overlay || temporary)
+      && (animating || visible);
 
     const drawer = (
       <Paper
diff --git a/src/js/FileInputs/FileUpload.d.ts b/src/js/FileInputs/FileUpload.d.ts
index 56ade0f342..7811a6f56a 100644
--- a/src/js/FileInputs/FileUpload.d.ts
+++ b/src/js/FileInputs/FileUpload.d.ts
@@ -13,7 +13,7 @@ export interface FileUploadProps extends FileInputProps {
   onProgress?: (file: File, progress: number, event: Event) => void;
 }
 
-interface FileUploadComponent extends React.ComponentClass<FileUploadProps> {
+export interface FileUploadComponent extends React.ComponentClass<FileUploadProps> {
   abort(file: string | File): void;
 }
 
diff --git a/src/js/Grids/Cell.d.ts b/src/js/Grids/Cell.d.ts
index 72310f102d..ae194f7cfa 100644
--- a/src/js/Grids/Cell.d.ts
+++ b/src/js/Grids/Cell.d.ts
@@ -24,7 +24,7 @@ export interface CellProps extends Props {
   desktopHidden?: boolean;
 }
 
-interface CellComponent extends React.ComponentClass<CellProps> {
+export interface CellComponent extends React.ComponentClass<CellProps> {
   getClassName(props?: CellProps): string;
 }
 
diff --git a/src/js/Grids/Grid.d.ts b/src/js/Grids/Grid.d.ts
index 28d528fc87..ed4db12984 100644
--- a/src/js/Grids/Grid.d.ts
+++ b/src/js/Grids/Grid.d.ts
@@ -12,7 +12,7 @@ export interface GridProps extends Props {
   spacing?: number;
 }
 
-interface GridComponent extends React.ComponentClass<GridProps> {
+export interface GridComponent extends React.ComponentClass<GridProps> {
   getClassName(props?: GridProps): string;
 }
 
diff --git a/src/js/Grids/GridList.d.ts b/src/js/Grids/GridList.d.ts
index 5006a34ea4..20591c79be 100644
--- a/src/js/Grids/GridList.d.ts
+++ b/src/js/Grids/GridList.d.ts
@@ -16,7 +16,7 @@ export interface GridListProps extends Props, GridProps, CellProps {
   cellClassName?: string;
 }
 
-interface GridListComponent extends React.ComponentClass<GridListProps> {
+export interface GridListComponent extends React.ComponentClass<GridListProps> {
   getClassNames(props?: GridListProps): { className: string, cellClassName: string };
 }
 
diff --git a/src/js/Helpers/AccessibleFakeButton.d.ts b/src/js/Helpers/AccessibleFakeButton.d.ts
index e2682757be..bfa803c853 100644
--- a/src/js/Helpers/AccessibleFakeButton.d.ts
+++ b/src/js/Helpers/AccessibleFakeButton.d.ts
@@ -15,7 +15,7 @@ export interface AccessibleFakeButtonProps {
   children?: React.ReactNode;
 }
 
-interface AccessibleFakeButtonComponent extends React.ComponentClass<AccessibleFakeButtonProps> {
+export interface AccessibleFakeButtonComponent extends React.ComponentClass<AccessibleFakeButtonProps> {
   focus: () => void;
   blur: () => void;
 }
diff --git a/src/js/Helpers/Layover.d.ts b/src/js/Helpers/Layover.d.ts
index 91274734cf..b80f4cccd6 100644
--- a/src/js/Helpers/Layover.d.ts
+++ b/src/js/Helpers/Layover.d.ts
@@ -67,7 +67,7 @@ export interface LayoverProps extends SharedLayoverProps {
   simplified?: boolean;
 }
 
-interface LayoverComponent extends React.ComponentClass<LayoverProps> {
+export interface LayoverComponent extends React.ComponentClass<LayoverProps> {
   Positions: {
     TOP_LEFT: 'tl',
     TOP_RIGHT: 'tr',
diff --git a/src/js/Lists/ListItem.d.ts b/src/js/Lists/ListItem.d.ts
index 8bbf6b9d6c..b36b0e6635 100644
--- a/src/js/Lists/ListItem.d.ts
+++ b/src/js/Lists/ListItem.d.ts
@@ -71,7 +71,7 @@ export interface ListItemProps extends BaseListItemProps, InjectedInkProps {
   expanderIconClassName?: string;
 }
 
-interface ListItemComponent extends React.ComponentClass<ListItemProps> {
+export interface ListItemComponent extends React.ComponentClass<ListItemProps> {
   focus(): void;
   blur(): void;
 }
diff --git a/src/js/Menus/DropdownMenu.d.ts b/src/js/Menus/DropdownMenu.d.ts
index abd7617bd2..bea571c0fe 100644
--- a/src/js/Menus/DropdownMenu.d.ts
+++ b/src/js/Menus/DropdownMenu.d.ts
@@ -19,7 +19,7 @@ export interface DropdownMenuProps extends SharedDropdownMenuProps {
   children?: React.ReactElement<any>;
 }
 
-interface DropdownMenuComponent extends React.ComponentClass<DropdownMenuProps> {
+export interface DropdownMenuComponent extends React.ComponentClass<DropdownMenuProps> {
   Positions: LayoverPositions;
   HorizontalAnchors: HorizontalAnchors;
   VerticalAnchors: VerticalAnchors;
diff --git a/src/js/Menus/Menu.d.ts b/src/js/Menus/Menu.d.ts
index 85b3cb228d..0c8a0fe4a0 100644
--- a/src/js/Menus/Menu.d.ts
+++ b/src/js/Menus/Menu.d.ts
@@ -71,7 +71,7 @@ export interface MenuProps extends BaseMenuProps {
   expanderIconChildren?: React.ReactNode;
 }
 
-interface MenuComponent extends React.ComponentClass<MenuProps> {
+export interface MenuComponent extends React.ComponentClass<MenuProps> {
   Positions: LayoverPositions;
   HorizontalAnchors: HorizontalAnchors;
   VerticalAnchors: VerticalAnchors;
diff --git a/src/js/Menus/MenuButton.d.ts b/src/js/Menus/MenuButton.d.ts
index cf8b72cfd0..a4977eb93b 100644
--- a/src/js/Menus/MenuButton.d.ts
+++ b/src/js/Menus/MenuButton.d.ts
@@ -31,7 +31,7 @@ export interface MenuButtonProps extends SharedDropdownMenuProps, SharedButtonPr
   defaultOpen?: boolean;
 }
 
-interface MenuButtonComponent extends React.ComponentClass<MenuButtonProps> {
+export interface MenuButtonComponent extends React.ComponentClass<MenuButtonProps> {
   Positions: LayoverPositions;
   HorizontalAnchors: HorizontalAnchors;
   VerticalAnchors: VerticalAnchors;
diff --git a/src/js/NavigationDrawers/NavigationDrawer.d.ts b/src/js/NavigationDrawers/NavigationDrawer.d.ts
index 54922fa647..e710e992ab 100644
--- a/src/js/NavigationDrawers/NavigationDrawer.d.ts
+++ b/src/js/NavigationDrawers/NavigationDrawer.d.ts
@@ -93,7 +93,7 @@ export interface NavigationDrawerProps extends Props {
   persistentIconClassName?: string;
 }
 
-interface NavigationDrawerComponent extends React.ComponentClass<NavigationDrawerProps> {
+export interface NavigationDrawerComponent extends React.ComponentClass<NavigationDrawerProps> {
   DrawerTypes: {
     // Permanent drawers
     FULL_HEIGHT: 'full-height',
diff --git a/src/js/SelectFields/SelectField.d.ts b/src/js/SelectFields/SelectField.d.ts
index dd103c8a97..3cee2a1ce5 100644
--- a/src/js/SelectFields/SelectField.d.ts
+++ b/src/js/SelectFields/SelectField.d.ts
@@ -105,7 +105,7 @@ export interface SelectFieldProps extends SharedSelectFieldProps {
   iconClassName?: string;
 }
 
-interface SelectFieldComponent extends React.ComponentClass<SelectFieldProps> {
+export interface SelectFieldComponent extends React.ComponentClass<SelectFieldProps> {
   Positions: {
     TOP_LEFT: 'tl',
     TOP_RIGHT: 'tr',
diff --git a/src/js/Sliders/Slider.js b/src/js/Sliders/Slider.js
index 4d4f1dbb76..94f204e376 100644
--- a/src/js/Sliders/Slider.js
+++ b/src/js/Sliders/Slider.js
@@ -554,7 +554,7 @@ export default class Slider extends PureComponent {
    * @param {Object} target - The event target.
    * @return {Boolean} true if the target is in the text field.
    */
-  _isTextField = (target) => this._field && this._field.contains(target);
+  _isTextField = (target) => this._textField && this._textField.contains(target);
 
   /**
    * Updates the slider's thumb position and the slider's track fill width based
@@ -701,15 +701,15 @@ export default class Slider extends PureComponent {
     }
   };
 
-  /**
-   * Updates the slider with the `step` prop and calls the `onChange`
-   * function with the new value.
-   *
-   * @param {number} incrementedValue - The newly incremented value of the slider.
-   * @param {Object} e - Either the text field's change event, mouse down event, or
-   *    touch start event.
-   * @param {bool} disableTransition - Boolean if the jump's transition should be disabled.
-   */
+    /**
+     * Updates the slider with the `step` prop and calls the `onChange`
+     * function with the new value.
+     *
+     * @param {number} incrementedValue - The newly incremented value of the slider.
+     * @param {Object} e - Either the text field's change event, mouse down event, or
+     *    touch start event.
+     * @param {bool} disableTransition - Boolean if the jump's transition should be disabled.
+     */
   _handleIncrement = (incrementedValue, e, disableTransition) => {
     const { onChange, min, max, discrete } = this.props;
 
@@ -814,7 +814,7 @@ export default class Slider extends PureComponent {
     if (!leftIcon && !rightIcon && !editable) {
       trackWidth = '100%';
     } else if (editable && !leftIcon) {
-      const cs = window.getComputedStyle(this._field);
+      const cs = window.getComputedStyle(this._textField);
       const pl = parseInt(cs.getPropertyValue('padding-left'), 10);
       const ml = parseInt(cs.getPropertyValue('margin-left'), 10);
 
diff --git a/src/js/TextFields/TextField.d.ts b/src/js/TextFields/TextField.d.ts
index fc886ceabe..7238819370 100644
--- a/src/js/TextFields/TextField.d.ts
+++ b/src/js/TextFields/TextField.d.ts
@@ -75,11 +75,10 @@ export interface TextFieldProps extends SharedTextFieldProps, Props {
   adjustMinWidth?: boolean;
 }
 
-interface TextFieldComponent extends React.ComponentClass<TextFieldProps> {
+export interface TextFieldComponent extends React.ComponentClass<TextFieldProps> {
   focus(): void;
   getField(): React.ReactHTMLElement<any> | null; // should be input or textarea, but get warning
 }
 
 declare const TextField: TextFieldComponent;
 export default TextField;
-
diff --git a/src/js/utils/EventUtils/handleKeyboardAccessibility.js b/src/js/utils/EventUtils/handleKeyboardAccessibility.js
index 848569929c..5480d1b688 100644
--- a/src/js/utils/EventUtils/handleKeyboardAccessibility.js
+++ b/src/js/utils/EventUtils/handleKeyboardAccessibility.js
@@ -31,7 +31,7 @@ export default function handleKeyboardAccessibility(e, onClick, listenToEnter =
   const enter = key === ENTER;
 
   const { tagName } = e.target;
-  if (space && !tagName.match(/input|textarea|button/i)) { // it is valid to press space in text fields and buttons
+  if (space && (tagName !== 'INPUT' && tagName !== 'TEXTAREA')) { // it is valid to press space in text fields
     // Stop page scrolling
     e.preventDefault();
   }


Test patch:
diff --git a/src/js/utils/EventUtils/__tests__/handleKeyboardAccessibility.js b/src/js/utils/EventUtils/__tests__/handleKeyboardAccessibility.js
index b54dd3a332..2e4ba9031c 100644
--- a/src/js/utils/EventUtils/__tests__/handleKeyboardAccessibility.js
+++ b/src/js/utils/EventUtils/__tests__/handleKeyboardAccessibility.js
@@ -6,11 +6,11 @@ import closest from '../../closest';
 import { ENTER, SPACE } from '../../../constants/keyCodes';
 
 const preventDefault = jest.fn();
-const FAKE_BUTTON = { getAttribute: jest.fn(() => 'button'), tagName: 'DIV' };
+const FAKE_BUTTON = { getAttribute: jest.fn(() => 'button') };
 
-const FAKE_RADIO = { getAttribute: jest.fn(() => 'radio'), tagName: 'DIV' };
+const FAKE_RADIO = { getAttribute: jest.fn(() => 'radio') };
 
-const FAKE_CHECKBOX = { getAttribute: jest.fn(() => 'checkbox'), tagName: 'DIV' };
+const FAKE_CHECKBOX = { getAttribute: jest.fn(() => 'checkbox') };
 
 describe('handleKeyboardAccessibility', () => {
   it('should trigger the onClick callback when listenToEnter is true and the enter key was pressed', () => {
@@ -65,21 +65,4 @@ describe('handleKeyboardAccessibility', () => {
     expect(form.querySelector).toBeCalledWith('*[type="submit"]');
     expect(submit.click).toBeCalled();
   });
-
-  it('should not prevent the default behavior if the spacebar is pressed on an input, textarea, or button', () => {
-    const cancelled = jest.fn();
-    const button = { tagName: 'BUTTON', getAttribute: () => '' };
-    const input = { tagName: 'INPUT', getAttribute: () => '' };
-    const area = { tagName: 'TEXTAREA', getAttribute: () => '' };
-
-    const onClick = jest.fn();
-    const event1 = { which: SPACE, keyCode: SPACE, target: button, preventDefault: cancelled };
-    const event2 = { which: SPACE, keyCode: SPACE, target: input, preventDefault: cancelled };
-    const event3 = { which: SPACE, keyCode: SPACE, target: area, preventDefault: cancelled };
-
-    handleKeyboardAccessibility(event1, onClick);
-    handleKeyboardAccessibility(event2, onClick);
-    handleKeyboardAccessibility(event3, onClick);
-    expect(onClick.mock.calls.length).toBe(3);
-  });
 });