UNPKG

material-ripple-button

Version:

React Ripple Button is similar to Material Design Button and may be used in standalone React applications or in conjunction with a CSS framework such as TailwindCSS.

366 lines (365 loc) 14.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i]; return arr2; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _extends() { _extends = Object.assign || function(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i]; for(var key in source){ if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function() { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){ _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally{ try { if (!_n && _i["return"] != null) _i["return"](); } finally{ if (_d) throw _e; } } return _arr; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for(i = 0; i < sourceSymbolKeys.length; i++){ key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for(i = 0; i < sourceKeys.length; i++){ key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function onBlurDeleteSpan(event) { var btn = event.currentTarget; // select all span with class "ripple" or "focusripple" var spans = btn.querySelectorAll("span.tallisfocusripple"); // delete all span for(var i = 0; i < spans.length; i++){ spans[i].remove(); } } function rippleColor() { var r = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : 0, g = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0, b = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 0, isDark = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : 0, source = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 0; var isBG = source === 0; var lightenColor; if (isDark) { if (!isBG) { lightenColor = "rgba(".concat(r * 0.5, ", ").concat(g * 0.5, ", ").concat(b * 0.5, ", 0.5)"); } else { lightenColor = "rgba(".concat(Math.min(r * 1.5, 255), ", ").concat(Math.min(g * 1.5, 255), ", ").concat(Math.min(b * 1.5, 255), ", 0.5)"); } } else { if (isBG) { lightenColor = "rgba(".concat(Math.min(r * 1.5, 255), ", ").concat(Math.min(g * 1.5, 255), ", ").concat(Math.min(b * 1.5, 255), ", 0.5)"); } else { lightenColor = "rgba(".concat(r * 0.5, ", ").concat(g * 0.5, ", ").concat(b * 0.5, ", 0.5)"); } } return lightenColor; } function focusRippleEffect(event) { event.stopPropagation(); var btn = event.currentTarget; // clear focus ripple span if it exists var focusRipple = btn.querySelector("span.ripple"); if (focusRipple) { return; } var circle = document.createElement("span"); var radius = Math.sqrt(btn.clientWidth * btn.clientWidth, btn.clientHeight * btn.clientHeight); var diameter = radius * 2; var position = btn.getBoundingClientRect(); circle.style.width = circle.style.height = "".concat(diameter, "px"); circle.style.left = "-".concat(position.width / 2, "px"); circle.style.top = "-".concat(radius - position.height / 2, "px"); // get the background color of the button, then lighten that color and set it as the ripple color background var source = 0; var pickedColor = window.getComputedStyle(btn).getPropertyValue("background-color"); // if there is no background color, use the text or border color if border color width is greater than 0 if (Number(window.getComputedStyle(btn).getPropertyValue("border-width").replace("px", "")) > 0 && (!pickedColor || [ "transparent", "rgba(0, 0, 0, 0)", "rgb(0, 0, 0)" ].includes(pickedColor))) { pickedColor = window.getComputedStyle(btn).getPropertyValue("border-color"); source = 1; } if (!pickedColor || [ "transparent", "rgba(0, 0, 0, 0)", "rgb(0, 0, 0)" ].includes(pickedColor)) { pickedColor = window.getComputedStyle(btn).getPropertyValue("color"); source = 2; } // if not, default is lightblue if (!pickedColor || [ "transparent" ].includes(pickedColor)) { pickedColor = "rgb(33, 150, 243)"; source = 3; } // lighten rgb color by 50% var rgb = pickedColor.match(/\d+/g); var r = Number(rgb[0]); var g = Number(rgb[1]); var b = Number(rgb[2]); var lightenColor; // if the color is nearly black, make it lighter and vice versa if (r + g + b > 382.5) { lightenColor = rippleColor(r, g, b, false, source); } else { lightenColor = rippleColor(r, g, b, true, source); } circle.style.backgroundColor = "".concat(lightenColor); circle.style.filter = "brightness(1.5)"; circle.classList.add("tallisfocusripple"); btn.appendChild(circle); // delete this from the dom after 6s (3 loops of ripple animation) setTimeout(function() { circle.remove(); }, 6000); } function rippleEffect(event) { event.stopPropagation(); var btn = event.currentTarget; // clear focus ripple span if it exists var focusRipple = btn.querySelector("span.focusripple"); if (focusRipple) { focusRipple.remove(); } var circle = document.createElement("span"); var radius = Math.sqrt(btn.clientWidth * btn.clientWidth, btn.clientHeight * btn.clientHeight); var diameter = radius * 2; var position = btn.getBoundingClientRect(); circle.style.width = circle.style.height = "".concat(diameter, "px"); circle.style.left = "".concat((event.clientX || event.touches[0].clientX) - (position.left + radius), "px"); circle.style.top = "".concat((event.clientY || event.touches[0].clientY) - (position.top + radius), "px"); // get the background color of the button, then lighten that color and set it as the ripple color background var source = 0; var pickedColor = window.getComputedStyle(btn).getPropertyValue("background-color"); // if there is no background color, use the text or border color if border color width is greater than 0 if (Number(window.getComputedStyle(btn).getPropertyValue("border-width").replace("px", "")) > 0 && (!pickedColor || [ "transparent", "rgba(0, 0, 0, 0)", "rgb(0, 0, 0)" ].includes(pickedColor))) { pickedColor = window.getComputedStyle(btn).getPropertyValue("border-color"); source = 1; } if (!pickedColor || [ "transparent", "rgba(0, 0, 0, 0)", "rgb(0, 0, 0)" ].includes(pickedColor)) { pickedColor = window.getComputedStyle(btn).getPropertyValue("color"); source = 2; } // if not, default is lightblue if (!pickedColor || [ "transparent" ].includes(pickedColor)) { pickedColor = "rgb(33, 150, 243)"; source = 3; } // lighten rgb color by 50% var rgb = pickedColor.match(/\d+/g); var r = Number(rgb[0]); var g = Number(rgb[1]); var b = Number(rgb[2]); var lightenColor; // if the color is nearly black, make it lighter and vice versa if (r + g + b > 382.5) { lightenColor = rippleColor(r, g, b, false, source); } else { lightenColor = rippleColor(r, g, b, true, source); } circle.style.backgroundColor = "".concat(lightenColor); circle.style.filter = "brightness(1.5)"; circle.classList.add("tallisripple"); btn.appendChild(circle); // delete this from the dom after 1s setTimeout(function() { circle.remove(); }, 1000); } var addEventToButtons = function() { var isTouchDevice = false; // check if is touch device if (window.matchMedia("(pointer: coarse)").matches) { isTouchDevice = true; } // add event to all buttons that not has disableRipple attribute var buttons = document.querySelectorAll("button:not([data-noripple])"); for(var i = 0; i < buttons.length; i++){ // remove old event buttons[i].removeEventListener("touchstart", rippleEffect, { passive: true }); buttons[i].removeEventListener("mousedown", rippleEffect, { passive: true }); buttons[i].removeEventListener("focus", focusRippleEffect, { passive: true }); buttons[i].removeEventListener("blur", onBlurDeleteSpan, { passive: true }); isTouchDevice ? buttons[i].addEventListener("touchstart", rippleEffect, { passive: true }) : buttons[i].addEventListener("mousedown", rippleEffect, { passive: true }); buttons[i].addEventListener("focus", focusRippleEffect, { passive: true }); buttons[i].addEventListener("blur", onBlurDeleteSpan, { passive: true }); } }; var RippleButton = function(_param) { var children = _param.children, props = _objectWithoutProperties(_param, [ "children" ]); var btnRef = (0, _react).useRef(null); var ref = _slicedToArray((0, _react).useState(false), 2), mounted = ref[0], setMounted = ref[1]; (0, _react).useEffect(function() { var btn = btnRef === null || btnRef === void 0 ? void 0 : btnRef.current; if (window !== undefined && mounted && btn) { btn.classList.add("tallisbutton"); addEventToButtons(btn); // on resize check if is touch device window.addEventListener("resize", function() { return addEventToButtons(btn); }, { passive: true }); // check if is there any style tag with id "style-tallisripple" var styleTag = document.getElementById("style-tallisripple"); if (!styleTag) { var style = document.createElement("style"); style.id = "style-tallisripple"; // add some styles style.innerHTML = css; document.head.appendChild(style); } } }, [ mounted ]); (0, _react).useEffect(function() { window && setMounted(true); }, []); if (mounted) { return /*#__PURE__*/ _react.default.createElement("button", _extends({ ref: btnRef }, props), children); } else { return /*#__PURE__*/ _react.default.createElement("div", null); } }; var css = "\n span.tallisripple {\n position: absolute;\n border-radius: 50%;\n transform: scale(0);\n animation: tallisripple 1s ease;\n background-color: rgba(255, 255, 255, 0.7);\n }\n @keyframes tallisripple {\n to {\n transform: scale(1);\n opacity: 0;\n }\n }\n span.tallisfocusripple {\n position: absolute;\n border-radius: 50%;\n transform: scale(0);\n animation: tallisfocusripple 2s ease-in-out;\n animation-iteration-count: 3;\n background-color: rgba(255, 255, 255, 0.7);\n }\n \n @keyframes tallisfocusripple {\n 0%,\n 100% {\n transform: scale(40%);\n opacity: 0.5;\n }\n 50% {\n transform: scale(45%);\n opacity: 0.5;\n }\n }\n button.tallisbutton {\n overflow: hidden;\n position: relative;\n -webkit-tap-highlight-color: transparent;\n }\n"; var _default = RippleButton; exports.default = _default;