Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
refactor(utils): refactored UserInteractionMode hooks and components
This moved all the "logic" into a single hook and added new tests for
this behavior. This also renamed the `InteractionModeListener` to
`UserInteractionModeListener` for more consistency, but still has the
old name available until the next major release. It has been marked as
deprecated which _should_ be caught by editors/IDEs.

> This also reduces the bundle size... by a small amount

```sh
The gizipped UMD bundle sizes are:
 - dist/umd/react-md.production.min.js 97.35 KB (- 1 B)
 - dist/umd/react-md-with-font-icons.production.min.js 120.39 KB (- 4 B)
 - dist/umd/react-md-with-svg-icons.production.min.js 186.74 KB (- 6 B)
```
  • Loading branch information
mlaursen committed Feb 6, 2021
1 parent ad59e80 commit af72791
Show file tree
Hide file tree
Showing 13 changed files with 388 additions and 241 deletions.
6 changes: 3 additions & 3 deletions packages/layout/src/Configuration.tsx
Expand Up @@ -24,7 +24,7 @@ import {
DEFAULT_TABLET_MAX_WIDTH,
DEFAULT_TABLET_MIN_WIDTH,
Dir,
InteractionModeListener,
UserInteractionModeListener,
WritingDirection,
} from "@react-md/utils";

Expand Down Expand Up @@ -115,7 +115,7 @@ export function Configuration({
desktopLargeMinWidth={desktopLargeMinWidth}
>
<NestedDialogContextProvider>
<InteractionModeListener>
<UserInteractionModeListener>
<StatesConfig
disableRipple={disableRipple}
disableProgrammaticRipple={disableProgrammaticRipple}
Expand All @@ -134,7 +134,7 @@ export function Configuration({
</IconProvider>
</TooltipHoverModeConfig>
</StatesConfig>
</InteractionModeListener>
</UserInteractionModeListener>
</NestedDialogContextProvider>
</AppSizeListener>
</Dir>
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/index.ts
@@ -1,7 +1,7 @@
export * from "./colors";
export * from "./events";
export * from "./interaction";
export * from "./layout";
export * from "./mode";
export * from "./search";
export * from "./sizing";
export * from "./positioning";
Expand Down
65 changes: 0 additions & 65 deletions packages/utils/src/interaction/InteractionMode.tsx

This file was deleted.

6 changes: 0 additions & 6 deletions packages/utils/src/interaction/index.ts

This file was deleted.

42 changes: 0 additions & 42 deletions packages/utils/src/interaction/useKeyboardDetection.ts

This file was deleted.

20 changes: 0 additions & 20 deletions packages/utils/src/interaction/useModeClassName.ts

This file was deleted.

30 changes: 0 additions & 30 deletions packages/utils/src/interaction/useModeDetection.ts

This file was deleted.

74 changes: 0 additions & 74 deletions packages/utils/src/interaction/useTouchDetection.ts

This file was deleted.

105 changes: 105 additions & 0 deletions packages/utils/src/mode/UserInteractionModeListener.tsx
@@ -0,0 +1,105 @@
import React, {
createContext,
ReactElement,
ReactNode,
useContext,
} from "react";

import { UserInteractionMode } from "./types";
import { useInteractionMode } from "./useInteractionMode";

/**
* @private
*/
const modeContext = createContext<UserInteractionMode>("mouse");

/**
* @private
*/
const parentContext = createContext(false);

/**
* @private
*/
const { Provider: UserInteractionModeProvider } = modeContext;

/**
* @private
*/
const { Provider: ParentProvider } = parentContext;

/**
* Returns the current user interaction mode.
*
* @return {@link UserInteractionMode}
*/
export function useUserInteractionMode(): UserInteractionMode {
return useContext(modeContext);
}

/**
* Example:
*
* ```ts
* const isKeyboard = useIsUserInteractionMode("keyboard");
* // do stuff if keyboard only
* ```
*
* @param mode The {@link UserInteractionMode} to check against.
* @return `true` if the current user interaction mode matches the provided
* mode.
*/
export function useIsUserInteractionMode(mode: UserInteractionMode): boolean {
return useInteractionMode() === mode;
}

export interface UserInteractionModeListenerProps {
/**
* The `children` are required since this component basically does nothing
* other than providing a `className` to the `document.body` otherwise.
*/
children: ReactNode;
}

/**
* This component is used to determine how the user is current interacting with
* your app as well as modifying the `document.body`'s `className` with the
* current mode. This is what allows the `rmd-utils-phone-only`,
* `rmd-utils-keyboard-only`, and `rmd-utils-mouse-only` mixins to work.
*
* @since 2.6.0 Renamed from `InteractionModeListener`
* @throws When this component has been mounted multiple times in your app.
*/
export function UserInteractionModeListener({
children,
}: UserInteractionModeListenerProps): ReactElement {
const mode = useInteractionMode();
if (useContext(parentContext)) {
throw new Error(
"Mounted multiple `UserInteractionModeListener` components."
);
}

return (
<UserInteractionModeProvider value={mode}>
<ParentProvider value>{children}</ParentProvider>
</UserInteractionModeProvider>
);
}

/**
* @deprecated Use the `UserInteractionModeListener` component instead.
* @since 2.6.0
*/
export const InteractionModeListener = UserInteractionModeListener;

/* istanbul ignore next */
if (process.env.NODE_ENV !== "production") {
try {
const PropTypes = require("prop-types");

UserInteractionModeListener.propTypes = {
children: PropTypes.node.isRequired,
};
} catch (e) {}
}

0 comments on commit af72791

Please sign in to comment.