Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@react-md/states

Package Overview
Dependencies
Maintainers
1
Versions
62
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@react-md/states - npm Package Compare versions

Comparing version 2.0.0-alpha.1 to 2.0.0-alpha.3

CHANGELOG.md

1

es/index.js
export * from "./useInteractionStates";
export { default as StatesConfig } from "./StatesConfig";
export * from "./StatesConfig";
export { InteractionModeListener, useInteractionModeContext, } from "./InteractionMode";
//# sourceMappingURL=index.js.map

10

es/ripples/reducer.js

@@ -12,4 +12,5 @@ var __assign = (this && this.__assign) || function () {

};
import { useCallback, useEffect, useReducer, useRef } from "react";
import { isRippleable, isBubbled, createRippleState, getType } from "./utils";
import { useCallback, useReducer } from "react";
import { useRefCache } from "@react-md/utils";
import { createRippleState, getType, isBubbled, isRippleable } from "./utils";
export var CREATE = "CREATE";

@@ -120,6 +121,3 @@ export var CANCEL = "CANCEL";

var _a = useReducer(reducer, []), state = _a[0], dispatch = _a[1];
var spacebarRef = useRef(disableSpacebarClick);
useEffect(function () {
spacebarRef.current = disableSpacebarClick;
});
var spacebarRef = useRefCache(disableSpacebarClick);
var create = useCallback(function (event) {

@@ -126,0 +124,0 @@ var disableSpacebarClick = spacebarRef.current;

@@ -1,4 +0,5 @@

import React, { useCallback, useEffect, useRef, } from "react";
import React, { useCallback } from "react";
import cn from "classnames";
import { CSSTransition } from "react-transition-group";
import { useRefCache } from "@react-md/utils";
import { useStatesConfigContext } from "../StatesConfig";

@@ -19,6 +20,3 @@ var Ripple = function (props) {

}
var ref = useRef({ ripple: ripple, entered: entered, exited: exited });
useEffect(function () {
ref.current = { ripple: ripple, entered: entered, exited: exited };
});
var ref = useRefCache({ ripple: ripple, entered: entered, exited: exited });
var onEntered = useCallback(function () {

@@ -25,0 +23,0 @@ var _a = ref.current, ripple = _a.ripple, entered = _a.entered;

@@ -12,3 +12,4 @@ var __assign = (this && this.__assign) || function () {

};
import { useCallback, useRef, useEffect } from "react";
import { useCallback } from "react";
import { useRefCache } from "@react-md/utils";
/**

@@ -24,6 +25,3 @@ * This hook is used to create all the event handlers required for

var disabled = propDisabled || disableRipple;
var ref = useRef(__assign({}, handlers, { disableProgrammaticRipple: disableProgrammaticRipple }));
useEffect(function () {
ref.current = __assign({}, handlers, { disableProgrammaticRipple: disableProgrammaticRipple });
});
var ref = useRefCache(__assign({}, handlers, { disableProgrammaticRipple: disableProgrammaticRipple }));
var onKeyDown = useCallback(function (event) {

@@ -30,0 +28,0 @@ var callback = ref.current.onKeyDown;

@@ -0,1 +1,2 @@

import { findSizingContainer } from "@react-md/utils";
/**

@@ -43,3 +44,5 @@ * Checks if the ripple event should be ignored since it was bubbled

case "keydown":
return ((!disableSpacebarClick && event.key === " ") || event.key === "Enter");
return ((!disableSpacebarClick && event.key === " ") ||
(event.key === "Enter" &&
!/checkbox|radio/i.test(event.currentTarget.getAttribute("type") || "")));
case "touchstart":

@@ -109,3 +112,3 @@ case "click":

export function createRippleState(event) {
var element = event.currentTarget;
var element = findSizingContainer(event.currentTarget) || event.currentTarget;
var offsetWidth = element.offsetWidth, offsetHeight = element.offsetHeight;

@@ -112,0 +115,0 @@ var type = getType(event);

import React, { createContext, useContext, useMemo, } from "react";
import { RIPPLE_CLASS_NAMES, RIPPLE_TIMEOUT } from "./ripples/contants";
import { useModeClassName, useModeDetection, } from "./useModeDetection";
export var StatesConfigContext = createContext({

@@ -9,3 +8,2 @@ rippleTimeout: RIPPLE_TIMEOUT,

disableProgrammaticRipple: false,
mode: "keyboard",
});

@@ -30,14 +28,4 @@ /**

var StatesConfig = function (props) {
var _a = props, rippleTimeout = _a.rippleTimeout, rippleClassNames = _a.rippleClassNames, disableRipple = _a.disableRipple, disableProgrammaticRipple = _a.disableProgrammaticRipple, disableModeDetection = _a.disableModeDetection, children = _a.children;
var mode;
if (disableModeDetection) {
var context = useStatesConfigContext();
mode = context.mode;
}
else {
var mode_1 = useModeDetection();
useModeClassName(mode_1);
}
var _a = props, rippleTimeout = _a.rippleTimeout, rippleClassNames = _a.rippleClassNames, disableRipple = _a.disableRipple, disableProgrammaticRipple = _a.disableProgrammaticRipple, children = _a.children;
var value = useMemo(function () { return ({
mode: mode,
rippleTimeout: rippleTimeout,

@@ -55,3 +43,2 @@ rippleClassNames: rippleClassNames,

disableProgrammaticRipple: false,
disableModeDetection: false,
};

@@ -58,0 +45,0 @@ StatesConfig.defaultProps = defaultProps;

@@ -1,2 +0,3 @@

import { useRef, useEffect, useCallback } from "react";
import { useCallback } from "react";
import { useRefCache } from "@react-md/utils";
/**

@@ -19,24 +20,31 @@ * This small utility function will create an onKeyDown handler that

if (disableSpacebarClick === void 0) { disableSpacebarClick = false; }
var ref = useRef(onKeyDown);
useEffect(function () {
ref.current = onKeyDown;
});
var ref = useRefCache({ onKeyDown: onKeyDown, disableSpacebarClick: disableSpacebarClick });
var handleKeyDown = useCallback(function (event) {
var onKeyDown = ref.current;
var _a = ref.current, onKeyDown = _a.onKeyDown, disableSpacebarClick = _a.disableSpacebarClick;
if (onKeyDown) {
onKeyDown(event);
}
var isSpace = event.key === " ";
var isEnter = event.key === "Enter";
var currentTarget = event.currentTarget;
var isEnter = event.key === "Enter";
var isSpace = !disableSpacebarClick &&
currentTarget.tagName !== "A" &&
event.key === " ";
if (!isSpace && !isEnter) {
var tagName = currentTarget.tagName;
var type = currentTarget.getAttribute("type") || "";
if ((!isSpace && !isEnter) ||
(isSpace && disableSpacebarClick) ||
// buttons and textareas shouldn't be polyfilled
/BUTTON|TEXTAREA/.test(tagName) ||
// checkboxes and radios submit forms on enter instead of clicking the element
(isEnter && /checkbox|radio/i.test(type)) ||
// native links don't click on space
(isSpace && tagName === "A")) {
return;
}
if (isSpace) {
// prevent page from scrolling
// prevent default behavior of page scrolling
event.preventDefault();
}
currentTarget.click();
// don't want parent keydown events to be triggered since this should now
// be a "click" event instead.
event.stopPropagation();
event.currentTarget.click();
}, []);

@@ -43,0 +51,0 @@ return disabled ? onKeyDown : handleKeyDown;

@@ -1,2 +0,3 @@

import { useState, useRef, useEffect, useCallback } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { useRefCache, useToggle } from "@react-md/utils";
/**

@@ -6,2 +7,5 @@ * This is a small hook that is used to determine if the app is currently

* between mousemove and touchstart events to determine which mode you are in.
* This also tracks the `contextmenu` appearance since long touchs can trigger
* the context menu on mobile devices. When the context menu appears after a touch,
* the mode will still be considered "touch" instead of swapping to mouse.
*

@@ -14,16 +18,17 @@ * @param touchTimeout - This is the amount of time that can occur between a

* @return true if the app is in touch mode.
* @private
*/
export function useTouchDetection(touchTimeout) {
if (touchTimeout === void 0) { touchTimeout = 500; }
if (touchTimeout === void 0) { touchTimeout = 1200; }
var _a = useState(0), lastTouchTime = _a[0], setTouchTime = _a[1];
var touchRef = useRef(lastTouchTime);
useEffect(function () {
touchRef.current = lastTouchTime;
});
var touchRef = useRefCache(lastTouchTime);
var contextMenuRef = useRef(false);
var updateTouchTime = useCallback(function () {
setTouchTime(Date.now());
contextMenuRef.current = false;
}, []);
var resetTouchTime = useCallback(function () {
var lastTouchTime = touchRef.current;
if (Date.now() - lastTouchTime < touchTimeout) {
if (contextMenuRef.current || Date.now() - lastTouchTime < touchTimeout) {
contextMenuRef.current = false;
return;

@@ -40,7 +45,14 @@ }

useEffect(function () {
if (lastTouchTime !== 0) {
window.addEventListener("mousemove", resetTouchTime, true);
if (lastTouchTime === 0) {
contextMenuRef.current = false;
return;
}
var updateContextMenu = function () {
contextMenuRef.current = true;
};
window.addEventListener("mousemove", resetTouchTime, true);
window.addEventListener("contextmenu", updateContextMenu, true);
return function () {
window.removeEventListener("mousemove", resetTouchTime, true);
window.removeEventListener("contextmenu", updateContextMenu, true);
};

@@ -55,20 +67,7 @@ }, [lastTouchTime]);

* @return true if the app is in keyboard mode
* @private
*/
export function useKeyboardDetection() {
var _a = useState(false), enabled = _a[0], setEnabled = _a[1];
var ref = useRef(enabled);
var _a = useToggle(), enabled = _a.toggled, enable = _a.enable, disable = _a.disable;
useEffect(function () {
ref.current = enabled;
});
var enable = useCallback(function () {
if (!ref.current) {
setEnabled(true);
}
}, []);
var disable = useCallback(function () {
if (ref.current) {
setEnabled(false);
}
}, []);
useEffect(function () {
if (enabled) {

@@ -95,2 +94,8 @@ return;

}
/**
* This hook combines the touch and keyboard detection hooks and returns a string
* of the current interaction mode of the app/user.
*
* @private
*/
export function useModeDetection() {

@@ -107,2 +112,8 @@ var touch = useTouchDetection();

}
/**
* This hook will apply the current mode class name to the `document.body` so that the
* specific mode style mixins work as expected.
*
* @private
*/
export function useModeClassName(mode) {

@@ -109,0 +120,0 @@ useEffect(function () {

@@ -12,3 +12,4 @@ var __assign = (this && this.__assign) || function () {

};
import { useState, useRef, useCallback, useEffect } from "react";
import { useCallback, useState } from "react";
import { useRefCache } from "@react-md/utils";
/**

@@ -28,6 +29,3 @@ * This is a different version of the useRippleStates that will allow you to know

var _e = useState(false), pressed = _e[0], setPressed = _e[1];
var ref = useRef(__assign({}, handlers, { pressed: pressed }));
useEffect(function () {
ref.current = __assign({}, handlers, { pressed: pressed });
});
var ref = useRefCache(__assign({}, handlers, { pressed: pressed }));
var handleKeyDown = useCallback(function (event) {

@@ -34,0 +32,0 @@ var _a = ref.current, onKeyDown = _a.onKeyDown, pressed = _a.pressed;

@@ -10,2 +10,5 @@ "use strict";

__export(require("./StatesConfig"));
var InteractionMode_1 = require("./InteractionMode");
exports.InteractionModeListener = InteractionMode_1.InteractionModeListener;
exports.useInteractionModeContext = InteractionMode_1.useInteractionModeContext;
//# sourceMappingURL=index.js.map

@@ -15,3 +15,4 @@ "use strict";

var react_1 = require("react");
var utils_1 = require("./utils");
var utils_1 = require("@react-md/utils");
var utils_2 = require("./utils");
exports.CREATE = "CREATE";

@@ -48,7 +49,7 @@ exports.CANCEL = "CANCEL";

function createRipple(state, event, disableSpacebarClick) {
if (!utils_1.isRippleable(event, disableSpacebarClick) || utils_1.isBubbled(event)) {
if (!utils_2.isRippleable(event, disableSpacebarClick) || utils_2.isBubbled(event)) {
return state;
}
else if (state.find(function (r) { return r.holding; }) ||
(utils_1.getType(event) !== "touch" && state.find(function (r) { return r.type === "touch"; }))) {
(utils_2.getType(event) !== "touch" && state.find(function (r) { return r.type === "touch"; }))) {
// keyboard events are a bit different than the others since it is actually

@@ -61,3 +62,3 @@ // spammable since the space or enter key can be held down which triggers click

}
var ripple = utils_1.createRippleState(event);
var ripple = utils_2.createRippleState(event);
return state.concat([ripple]);

@@ -126,6 +127,3 @@ }

var _a = react_1.useReducer(reducer, []), state = _a[0], dispatch = _a[1];
var spacebarRef = react_1.useRef(disableSpacebarClick);
react_1.useEffect(function () {
spacebarRef.current = disableSpacebarClick;
});
var spacebarRef = utils_1.useRefCache(disableSpacebarClick);
var create = react_1.useCallback(function (event) {

@@ -132,0 +130,0 @@ var disableSpacebarClick = spacebarRef.current;

@@ -16,2 +16,3 @@ "use strict";

var react_transition_group_1 = require("react-transition-group");
var utils_1 = require("@react-md/utils");
var StatesConfig_1 = require("../StatesConfig");

@@ -32,6 +33,3 @@ var Ripple = function (props) {

}
var ref = react_1.useRef({ ripple: ripple, entered: entered, exited: exited });
react_1.useEffect(function () {
ref.current = { ripple: ripple, entered: entered, exited: exited };
});
var ref = utils_1.useRefCache({ ripple: ripple, entered: entered, exited: exited });
var onEntered = react_1.useCallback(function () {

@@ -38,0 +36,0 @@ var _a = ref.current, ripple = _a.ripple, entered = _a.entered;

@@ -15,2 +15,3 @@ "use strict";

var react_1 = require("react");
var utils_1 = require("@react-md/utils");
/**

@@ -26,6 +27,3 @@ * This hook is used to create all the event handlers required for

var disabled = propDisabled || disableRipple;
var ref = react_1.useRef(__assign({}, handlers, { disableProgrammaticRipple: disableProgrammaticRipple }));
react_1.useEffect(function () {
ref.current = __assign({}, handlers, { disableProgrammaticRipple: disableProgrammaticRipple });
});
var ref = utils_1.useRefCache(__assign({}, handlers, { disableProgrammaticRipple: disableProgrammaticRipple }));
var onKeyDown = react_1.useCallback(function (event) {

@@ -32,0 +30,0 @@ var callback = ref.current.onKeyDown;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var utils_1 = require("@react-md/utils");
/**

@@ -47,3 +48,5 @@ * Checks if the ripple event should be ignored since it was bubbled

case "keydown":
return ((!disableSpacebarClick && event.key === " ") || event.key === "Enter");
return ((!disableSpacebarClick && event.key === " ") ||
(event.key === "Enter" &&
!/checkbox|radio/i.test(event.currentTarget.getAttribute("type") || "")));
case "touchstart":

@@ -115,3 +118,3 @@ case "click":

function createRippleState(event) {
var element = event.currentTarget;
var element = utils_1.findSizingContainer(event.currentTarget) || event.currentTarget;
var offsetWidth = element.offsetWidth, offsetHeight = element.offsetHeight;

@@ -118,0 +121,0 @@ var type = getType(event);

@@ -12,3 +12,2 @@ "use strict";

var contants_1 = require("./ripples/contants");
var useModeDetection_1 = require("./useModeDetection");
exports.StatesConfigContext = react_1.createContext({

@@ -19,3 +18,2 @@ rippleTimeout: contants_1.RIPPLE_TIMEOUT,

disableProgrammaticRipple: false,
mode: "keyboard",
});

@@ -41,14 +39,4 @@ /**

var StatesConfig = function (props) {
var _a = props, rippleTimeout = _a.rippleTimeout, rippleClassNames = _a.rippleClassNames, disableRipple = _a.disableRipple, disableProgrammaticRipple = _a.disableProgrammaticRipple, disableModeDetection = _a.disableModeDetection, children = _a.children;
var mode;
if (disableModeDetection) {
var context = useStatesConfigContext();
mode = context.mode;
}
else {
var mode_1 = useModeDetection_1.useModeDetection();
useModeDetection_1.useModeClassName(mode_1);
}
var _a = props, rippleTimeout = _a.rippleTimeout, rippleClassNames = _a.rippleClassNames, disableRipple = _a.disableRipple, disableProgrammaticRipple = _a.disableProgrammaticRipple, children = _a.children;
var value = react_1.useMemo(function () { return ({
mode: mode,
rippleTimeout: rippleTimeout,

@@ -66,3 +54,2 @@ rippleClassNames: rippleClassNames,

disableProgrammaticRipple: false,
disableModeDetection: false,
};

@@ -69,0 +56,0 @@ StatesConfig.defaultProps = defaultProps;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = require("react");
var utils_1 = require("@react-md/utils");
/**

@@ -21,24 +22,31 @@ * This small utility function will create an onKeyDown handler that

if (disableSpacebarClick === void 0) { disableSpacebarClick = false; }
var ref = react_1.useRef(onKeyDown);
react_1.useEffect(function () {
ref.current = onKeyDown;
});
var ref = utils_1.useRefCache({ onKeyDown: onKeyDown, disableSpacebarClick: disableSpacebarClick });
var handleKeyDown = react_1.useCallback(function (event) {
var onKeyDown = ref.current;
var _a = ref.current, onKeyDown = _a.onKeyDown, disableSpacebarClick = _a.disableSpacebarClick;
if (onKeyDown) {
onKeyDown(event);
}
var isSpace = event.key === " ";
var isEnter = event.key === "Enter";
var currentTarget = event.currentTarget;
var isEnter = event.key === "Enter";
var isSpace = !disableSpacebarClick &&
currentTarget.tagName !== "A" &&
event.key === " ";
if (!isSpace && !isEnter) {
var tagName = currentTarget.tagName;
var type = currentTarget.getAttribute("type") || "";
if ((!isSpace && !isEnter) ||
(isSpace && disableSpacebarClick) ||
// buttons and textareas shouldn't be polyfilled
/BUTTON|TEXTAREA/.test(tagName) ||
// checkboxes and radios submit forms on enter instead of clicking the element
(isEnter && /checkbox|radio/i.test(type)) ||
// native links don't click on space
(isSpace && tagName === "A")) {
return;
}
if (isSpace) {
// prevent page from scrolling
// prevent default behavior of page scrolling
event.preventDefault();
}
currentTarget.click();
// don't want parent keydown events to be triggered since this should now
// be a "click" event instead.
event.stopPropagation();
event.currentTarget.click();
}, []);

@@ -45,0 +53,0 @@ return disabled ? onKeyDown : handleKeyDown;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = require("react");
var utils_1 = require("@react-md/utils");
/**

@@ -8,2 +9,5 @@ * This is a small hook that is used to determine if the app is currently

* between mousemove and touchstart events to determine which mode you are in.
* This also tracks the `contextmenu` appearance since long touchs can trigger
* the context menu on mobile devices. When the context menu appears after a touch,
* the mode will still be considered "touch" instead of swapping to mouse.
*

@@ -16,16 +20,17 @@ * @param touchTimeout - This is the amount of time that can occur between a

* @return true if the app is in touch mode.
* @private
*/
function useTouchDetection(touchTimeout) {
if (touchTimeout === void 0) { touchTimeout = 500; }
if (touchTimeout === void 0) { touchTimeout = 1200; }
var _a = react_1.useState(0), lastTouchTime = _a[0], setTouchTime = _a[1];
var touchRef = react_1.useRef(lastTouchTime);
react_1.useEffect(function () {
touchRef.current = lastTouchTime;
});
var touchRef = utils_1.useRefCache(lastTouchTime);
var contextMenuRef = react_1.useRef(false);
var updateTouchTime = react_1.useCallback(function () {
setTouchTime(Date.now());
contextMenuRef.current = false;
}, []);
var resetTouchTime = react_1.useCallback(function () {
var lastTouchTime = touchRef.current;
if (Date.now() - lastTouchTime < touchTimeout) {
if (contextMenuRef.current || Date.now() - lastTouchTime < touchTimeout) {
contextMenuRef.current = false;
return;

@@ -42,7 +47,14 @@ }

react_1.useEffect(function () {
if (lastTouchTime !== 0) {
window.addEventListener("mousemove", resetTouchTime, true);
if (lastTouchTime === 0) {
contextMenuRef.current = false;
return;
}
var updateContextMenu = function () {
contextMenuRef.current = true;
};
window.addEventListener("mousemove", resetTouchTime, true);
window.addEventListener("contextmenu", updateContextMenu, true);
return function () {
window.removeEventListener("mousemove", resetTouchTime, true);
window.removeEventListener("contextmenu", updateContextMenu, true);
};

@@ -58,20 +70,7 @@ }, [lastTouchTime]);

* @return true if the app is in keyboard mode
* @private
*/
function useKeyboardDetection() {
var _a = react_1.useState(false), enabled = _a[0], setEnabled = _a[1];
var ref = react_1.useRef(enabled);
var _a = utils_1.useToggle(), enabled = _a.toggled, enable = _a.enable, disable = _a.disable;
react_1.useEffect(function () {
ref.current = enabled;
});
var enable = react_1.useCallback(function () {
if (!ref.current) {
setEnabled(true);
}
}, []);
var disable = react_1.useCallback(function () {
if (ref.current) {
setEnabled(false);
}
}, []);
react_1.useEffect(function () {
if (enabled) {

@@ -99,2 +98,8 @@ return;

exports.useKeyboardDetection = useKeyboardDetection;
/**
* This hook combines the touch and keyboard detection hooks and returns a string
* of the current interaction mode of the app/user.
*
* @private
*/
function useModeDetection() {

@@ -112,2 +117,8 @@ var touch = useTouchDetection();

exports.useModeDetection = useModeDetection;
/**
* This hook will apply the current mode class name to the `document.body` so that the
* specific mode style mixins work as expected.
*
* @private
*/
function useModeClassName(mode) {

@@ -114,0 +125,0 @@ react_1.useEffect(function () {

@@ -15,2 +15,3 @@ "use strict";

var react_1 = require("react");
var utils_1 = require("@react-md/utils");
/**

@@ -30,6 +31,3 @@ * This is a different version of the useRippleStates that will allow you to know

var _e = react_1.useState(false), pressed = _e[0], setPressed = _e[1];
var ref = react_1.useRef(__assign({}, handlers, { pressed: pressed }));
react_1.useEffect(function () {
ref.current = __assign({}, handlers, { pressed: pressed });
});
var ref = utils_1.useRefCache(__assign({}, handlers, { pressed: pressed }));
var handleKeyDown = react_1.useCallback(function (event) {

@@ -36,0 +34,0 @@ var _a = ref.current, onKeyDown = _a.onKeyDown, pressed = _a.pressed;

{
"name": "@react-md/states",
"version": "2.0.0-alpha.1",
"version": "2.0.0-alpha.3",
"description": "A package for adding the different focus, hover, selected, active, etc states to elements",
"scripts": {
"build": "dev-utils build",
"clean": "dev-utils clean",
"test": "dev-utils test"
"clean": "dev-utils clean"
},

@@ -32,5 +31,5 @@ "main": "./lib/index.js",

"dependencies": {
"@react-md/theme": "^2.0.0-alpha.1",
"@react-md/transition": "^2.0.0-alpha.1",
"@react-md/utils": "^2.0.0-alpha.1",
"@react-md/theme": "^2.0.0-alpha.3",
"@react-md/transition": "^2.0.0-alpha.3",
"@react-md/utils": "^2.0.0-alpha.3",
"react-transition-group": "^4.0.0"

@@ -47,3 +46,3 @@ },

},
"gitHead": "9197bcdf38df3cff304499431696dc8e950b4b17"
"gitHead": "ff38fa4bd502c527ffb8847eae71b471456e0355"
}

@@ -99,3 +99,3 @@ # @react-md/states

```tsx
import React, { HTMLAttributes } from "react";
import React, { FC, HTMLAttributes } from "react";
import { render } from "react-dom";

@@ -110,3 +110,3 @@ import {

InteractionStatesOptions<HTMLButtonElement>;
const Button: FunctionComponent<ButtonProps> = ({
const Button: FC<ButtonProps> = ({
className: propClassName,

@@ -113,0 +113,0 @@ disabled,

@@ -5,1 +5,6 @@ export * from "./useInteractionStates";

export * from "./StatesConfig";
export {
InteractionModeListener,
useInteractionModeContext,
} from "./InteractionMode";

@@ -68,5 +68,17 @@ import {

describe("isRippleable", () => {
const target = document.createElement("div");
const targets = { target, currentTarget: target };
const mouseDownEvent = {
...targets,
type: "mousedown",
button: 0,
};
const keyDownEvent = {
...targets,
type: "keydown",
key: " ",
};
it("should return true for a left mousedown click", () => {
expect(isRippleable({ type: "mousedown", button: 0 }, false)).toBe(true);
expect(isRippleable({ type: "mousedown", button: 0 }, true)).toBe(true);
expect(isRippleable(mouseDownEvent, false)).toBe(true);
expect(isRippleable(mouseDownEvent, true)).toBe(true);
});

@@ -78,4 +90,4 @@

expect(isRippleable({ type: "mousedown", button: 0 }, false)).toBe(false);
expect(isRippleable({ type: "mousedown", button: 0 }, true)).toBe(false);
expect(isRippleable(mouseDownEvent, false)).toBe(false);
expect(isRippleable(mouseDownEvent, true)).toBe(false);
expect(spy).toBeCalledWith(".rmd-states--touch");

@@ -88,16 +100,16 @@ expect(spy).toBeCalledTimes(2);

it("should return false if the mousedown button is not hte left mouse button", () => {
expect(isRippleable({ type: "mousedown", button: 1 }, false)).toBe(false);
expect(isRippleable({ type: "mousedown", button: 1 }, true)).toBe(false);
expect(isRippleable({ type: "mousedown", button: 2 }, false)).toBe(false);
expect(isRippleable({ type: "mousedown", button: 2 }, true)).toBe(false);
expect(isRippleable({ ...mouseDownEvent, button: 1 }, false)).toBe(false);
expect(isRippleable({ ...mouseDownEvent, button: 1 }, true)).toBe(false);
expect(isRippleable({ ...mouseDownEvent, button: 2 }, false)).toBe(false);
expect(isRippleable({ ...mouseDownEvent, button: 2 }, true)).toBe(false);
});
it("should return true if the keydown event was for the Enter key", () => {
expect(isRippleable({ type: "keydown", key: "Enter" }, false)).toBe(true);
expect(isRippleable({ type: "keydown", key: "Enter" }, true)).toBe(true);
expect(isRippleable({ ...keyDownEvent, key: "Enter" }, false)).toBe(true);
expect(isRippleable({ ...keyDownEvent, key: "Enter" }, true)).toBe(true);
});
it("should return true for a space keydown event based on the disableSpacebarClick value", () => {
expect(isRippleable({ type: "keydown", key: " " }, false)).toBe(true);
expect(isRippleable({ type: "keydown", key: " " }, true)).toBe(false);
expect(isRippleable({ ...keyDownEvent, key: " " }, false)).toBe(true);
expect(isRippleable({ ...keyDownEvent, key: " " }, true)).toBe(false);
});

@@ -140,4 +152,4 @@

keys.forEach(key => {
expect(isRippleable({ type: "keydown", key }, false)).toBe(false);
expect(isRippleable({ type: "keydown", key }, true)).toBe(false);
expect(isRippleable({ ...keyDownEvent, key }, false)).toBe(false);
expect(isRippleable({ ...keyDownEvent, key }, true)).toBe(false);
});

@@ -148,4 +160,4 @@ });

// don't know how to provide the touches as a TouchList
expect(isRippleable({ type: "touchstart" }, false)).toBe(true);
expect(isRippleable({ type: "touchstart" }, true)).toBe(true);
expect(isRippleable({ type: "touchstart", ...targets }, false)).toBe(true);
expect(isRippleable({ type: "touchstart", ...targets }, true)).toBe(true);
});

@@ -170,4 +182,4 @@

types.forEach(type => {
expect(isRippleable({ type }, false)).toBe(false);
expect(isRippleable({ type }, true)).toBe(false);
expect(isRippleable({ ...targets, type }, false)).toBe(false);
expect(isRippleable({ ...targets, type }, true)).toBe(false);
});

@@ -174,0 +186,0 @@ });

@@ -1,4 +0,5 @@

import { Reducer, useCallback, useEffect, useReducer, useRef } from "react";
import { RipplesState, RippleState, RippleEvent } from "./types.d";
import { isRippleable, isBubbled, createRippleState, getType } from "./utils";
import { Reducer, useCallback, useReducer } from "react";
import { useRefCache } from "@react-md/utils";
import { RippleEvent, RipplesState, RippleState } from "./types.d";
import { createRippleState, getType, isBubbled, isRippleable } from "./utils";

@@ -192,7 +193,3 @@ export const CREATE = "CREATE";

const [state, dispatch] = useReducer<RippleStateReducer<E>>(reducer, []);
const spacebarRef = useRef(disableSpacebarClick);
useEffect(() => {
spacebarRef.current = disableSpacebarClick;
});
const spacebarRef = useRefCache(disableSpacebarClick);
const create = useCallback((event: RippleEvent<E>) => {

@@ -199,0 +196,0 @@ const disableSpacebarClick = spacebarRef.current;

@@ -1,2 +0,4 @@

import { useCallback, useRef, useEffect } from "react";
import { useCallback } from "react";
import { useRefCache } from "@react-md/utils";
import { MergableRippleHandlers, RippleEvent } from "./types.d";

@@ -31,6 +33,3 @@

const disabled = propDisabled || disableRipple;
const ref = useRef({ ...handlers, disableProgrammaticRipple });
useEffect(() => {
ref.current = { ...handlers, disableProgrammaticRipple };
});
const ref = useRefCache({ ...handlers, disableProgrammaticRipple });

@@ -37,0 +36,0 @@ const onKeyDown = useCallback((event: React.KeyboardEvent<E>) => {

import { RippleEvent, RippleType, RippleState } from "./types.d";
import { findSizingContainer } from "@react-md/utils";

@@ -48,3 +49,3 @@ /**

export function isRippleable(
event: Pick<RippleEvent<HTMLElement>, "button" | "key" | "type">,
event: RippleEvent<HTMLElement>,
disableSpacebarClick: boolean

@@ -60,3 +61,7 @@ ) {

return (
(!disableSpacebarClick && event.key === " ") || event.key === "Enter"
(!disableSpacebarClick && event.key === " ") ||
(event.key === "Enter" &&
!/checkbox|radio/i.test(
event.currentTarget.getAttribute("type") || ""
))
);

@@ -147,3 +152,4 @@ case "touchstart":

): RippleState {
const element = event.currentTarget;
const element =
findSizingContainer(event.currentTarget) || event.currentTarget;
const { offsetWidth, offsetHeight } = element;

@@ -150,0 +156,0 @@ const type = getType(event);

import { ReactNode } from "react";
import cn from "classnames";
import { Maybe, Omit } from "@react-md/utils";
import { Maybe } from "@react-md/utils";

@@ -15,3 +15,3 @@ import { MergableRippleHandlers, RipplesOptions } from "./ripples/types.d";

export interface InteractionStatesOptions<E extends HTMLElement = HTMLElement>
extends Omit<Partial<StatesConfigContextType>, "mode">,
extends Partial<StatesConfigContextType>,
RipplesOptions<E> {

@@ -18,0 +18,0 @@ /**

@@ -1,2 +0,3 @@

import { useRef, useEffect, useCallback } from "react";
import { useCallback } from "react";
import { useRefCache } from "@react-md/utils";

@@ -24,9 +25,6 @@ /**

) {
const ref = useRef(onKeyDown);
useEffect(() => {
ref.current = onKeyDown;
});
const ref = useRefCache({ onKeyDown, disableSpacebarClick });
const handleKeyDown = useCallback((event: React.KeyboardEvent<E>) => {
const onKeyDown = ref.current;
const { onKeyDown, disableSpacebarClick } = ref.current;
if (onKeyDown) {

@@ -36,9 +34,17 @@ onKeyDown(event);

const isSpace = event.key === " ";
const isEnter = event.key === "Enter";
const { currentTarget } = event;
const isEnter = event.key === "Enter";
const isSpace =
!disableSpacebarClick &&
currentTarget.tagName !== "A" &&
event.key === " ";
if (!isSpace && !isEnter) {
const { tagName } = currentTarget;
const type = currentTarget.getAttribute("type") || "";
if (
(!isSpace && !isEnter) ||
(isSpace && disableSpacebarClick) ||
// buttons and textareas shouldn't be polyfilled
/BUTTON|TEXTAREA/.test(tagName) ||
// checkboxes and radios submit forms on enter instead of clicking the element
(isEnter && /checkbox|radio/i.test(type)) ||
// native links don't click on space
(isSpace && tagName === "A")
) {
return;

@@ -48,7 +54,10 @@ }

if (isSpace) {
// prevent page from scrolling
// prevent default behavior of page scrolling
event.preventDefault();
}
currentTarget.click();
// don't want parent keydown events to be triggered since this should now
// be a "click" event instead.
event.stopPropagation();
event.currentTarget.click();
}, []);

@@ -55,0 +64,0 @@

@@ -1,2 +0,3 @@

import { useState, useRef, useEffect, useCallback } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { useRefCache, useToggle } from "@react-md/utils";

@@ -14,2 +15,5 @@ /**

* between mousemove and touchstart events to determine which mode you are in.
* This also tracks the `contextmenu` appearance since long touchs can trigger
* the context menu on mobile devices. When the context menu appears after a touch,
* the mode will still be considered "touch" instead of swapping to mouse.
*

@@ -22,12 +26,12 @@ * @param touchTimeout - This is the amount of time that can occur between a

* @return true if the app is in touch mode.
* @private
*/
export function useTouchDetection(touchTimeout: number = 500) {
export function useTouchDetection(touchTimeout: number = 1200) {
const [lastTouchTime, setTouchTime] = useState(0);
const touchRef = useRef(lastTouchTime);
useEffect(() => {
touchRef.current = lastTouchTime;
});
const touchRef = useRefCache(lastTouchTime);
const contextMenuRef = useRef(false);
const updateTouchTime = useCallback(() => {
setTouchTime(Date.now());
contextMenuRef.current = false;
}, []);

@@ -37,3 +41,4 @@

const lastTouchTime = touchRef.current;
if (Date.now() - lastTouchTime < touchTimeout) {
if (contextMenuRef.current || Date.now() - lastTouchTime < touchTimeout) {
contextMenuRef.current = false;
return;

@@ -54,8 +59,16 @@ }

useEffect(() => {
if (lastTouchTime !== 0) {
window.addEventListener("mousemove", resetTouchTime, true);
if (lastTouchTime === 0) {
contextMenuRef.current = false;
return;
}
const updateContextMenu = () => {
contextMenuRef.current = true;
};
window.addEventListener("mousemove", resetTouchTime, true);
window.addEventListener("contextmenu", updateContextMenu, true);
return () => {
window.removeEventListener("mousemove", resetTouchTime, true);
window.removeEventListener("contextmenu", updateContextMenu, true);
};

@@ -72,22 +85,7 @@ }, [lastTouchTime]);

* @return true if the app is in keyboard mode
* @private
*/
export function useKeyboardDetection() {
const [enabled, setEnabled] = useState(false);
const ref = useRef(enabled);
useEffect(() => {
ref.current = enabled;
});
const { toggled: enabled, enable, disable } = useToggle();
const enable = useCallback(() => {
if (!ref.current) {
setEnabled(true);
}
}, []);
const disable = useCallback(() => {
if (ref.current) {
setEnabled(false);
}
}, []);
useEffect(() => {

@@ -122,2 +120,8 @@ if (enabled) {

/**
* This hook combines the touch and keyboard detection hooks and returns a string
* of the current interaction mode of the app/user.
*
* @private
*/
export function useModeDetection(): UserInteractionMode {

@@ -136,2 +140,8 @@ const touch = useTouchDetection();

/**
* This hook will apply the current mode class name to the `document.body` so that the
* specific mode style mixins work as expected.
*
* @private
*/
export function useModeClassName(mode: UserInteractionMode) {

@@ -138,0 +148,0 @@ useEffect(() => {

@@ -1,2 +0,4 @@

import { useState, useRef, useCallback, useEffect } from "react";
import { useCallback, useState } from "react";
import { useRefCache } from "@react-md/utils";
import { MergableRippleHandlers } from "./ripples/types.d";

@@ -25,9 +27,3 @@

const [pressed, setPressed] = useState(false);
const ref = useRef({ ...handlers, pressed });
useEffect(() => {
ref.current = {
...handlers,
pressed,
};
});
const ref = useRefCache({ ...handlers, pressed });

@@ -34,0 +30,0 @@ const handleKeyDown = useCallback((event: React.KeyboardEvent<E>) => {

export * from "./useInteractionStates";
export { default as StatesConfig } from "./StatesConfig";
export * from "./StatesConfig";
export { InteractionModeListener, useInteractionModeContext, } from "./InteractionMode";

@@ -1,2 +0,2 @@

import { RippleState, RippleEvent } from "./types.d";
import { RippleEvent, RippleState } from "./types.d";
export declare const CREATE = "CREATE";

@@ -3,0 +3,0 @@ export declare const CANCEL = "CANCEL";

@@ -1,2 +0,2 @@

import { FunctionComponent } from "react";
import { FC } from "react";
import { CSSTransitionClassNames, TransitionTimeout } from "@react-md/transition";

@@ -12,3 +12,3 @@ import { RippleState } from "./types.d";

}
declare const Ripple: FunctionComponent<RippleProps>;
declare const Ripple: FC<RippleProps>;
export default Ripple;

@@ -1,2 +0,2 @@

import { FunctionComponent } from "react";
import { FC } from "react";
import { CSSTransitionClassNames, TransitionTimeout } from "@react-md/transition";

@@ -13,3 +13,3 @@ import { RipplesState, RippleState } from "./types.d";

}
declare const RippleContainer: FunctionComponent<RippleContainerProps>;
declare const RippleContainer: FC<RippleContainerProps>;
export default RippleContainer;

@@ -20,3 +20,3 @@ import { RippleEvent, RippleType, RippleState } from "./types.d";

*/
export declare function isRippleable(event: Pick<RippleEvent<HTMLElement>, "button" | "key" | "type">, disableSpacebarClick: boolean): boolean;
export declare function isRippleable(event: RippleEvent<HTMLElement>, disableSpacebarClick: boolean): boolean;
/**

@@ -23,0 +23,0 @@ * Gets the ripple creation origin base on the provided event. When the event

@@ -1,4 +0,3 @@

import React, { FunctionComponent, ReactNode } from "react";
import React, { FC, ReactNode } from "react";
import { CSSTransitionClassNames, TransitionTimeout } from "@react-md/transition";
import { UserInteractionMode } from "./useModeDetection";
/**

@@ -30,6 +29,2 @@ * Contains all the values in the `StatesConfig` component.

disableProgrammaticRipple: boolean;
/**
* The user's current interaction mode with your app.
*/
mode: UserInteractionMode;
}

@@ -46,3 +41,2 @@ export declare const StatesConfigContext: React.Context<StatesConfigContextType>;

children?: ReactNode;
disableModeDetection?: boolean;
}

@@ -57,3 +51,3 @@ /**

*/
declare const StatesConfig: FunctionComponent<StatesConfigProps>;
declare const StatesConfig: FC<StatesConfigProps>;
export default StatesConfig;
/// <reference types="react" />
import { Omit } from "@react-md/utils";
import { RipplesOptions } from "./ripples/types.d";
import { StatesConfigContextType } from "./StatesConfig";
export interface InteractionStatesOptions<E extends HTMLElement = HTMLElement> extends Omit<Partial<StatesConfigContextType>, "mode">, RipplesOptions<E> {
export interface InteractionStatesOptions<E extends HTMLElement = HTMLElement> extends Partial<StatesConfigContextType>, RipplesOptions<E> {
/**

@@ -7,0 +6,0 @@ * An optional className to merge with the different interaction states.

@@ -11,2 +11,5 @@ /**

* between mousemove and touchstart events to determine which mode you are in.
* This also tracks the `contextmenu` appearance since long touchs can trigger
* the context menu on mobile devices. When the context menu appears after a touch,
* the mode will still be considered "touch" instead of swapping to mouse.
*

@@ -19,2 +22,3 @@ * @param touchTimeout - This is the amount of time that can occur between a

* @return true if the app is in touch mode.
* @private
*/

@@ -27,5 +31,18 @@ export declare function useTouchDetection(touchTimeout?: number): boolean;

* @return true if the app is in keyboard mode
* @private
*/
export declare function useKeyboardDetection(): boolean;
/**
* This hook combines the touch and keyboard detection hooks and returns a string
* of the current interaction mode of the app/user.
*
* @private
*/
export declare function useModeDetection(): UserInteractionMode;
/**
* This hook will apply the current mode class name to the `document.body` so that the
* specific mode style mixins work as expected.
*
* @private
*/
export declare function useModeClassName(mode: UserInteractionMode): void;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc