@uni-design-system/uni-react 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/button/button.component.js +2 -2
- package/dist/cjs/components/card/card.component.js +2 -3
- package/dist/cjs/components/modal/modal.component.js +3 -1
- package/dist/cjs/core/hooks/index.d.ts +0 -1
- package/dist/cjs/core/hooks/index.js +0 -1
- package/dist/esm/components/button/button.component.js +1 -1
- package/dist/esm/components/card/card.component.js +2 -3
- package/dist/esm/components/modal/modal.component.js +3 -1
- package/dist/esm/core/hooks/index.d.ts +0 -1
- package/dist/esm/core/hooks/index.js +0 -1
- package/package.json +4 -3
- package/dist/cjs/core/hooks/use-ripple.d.ts +0 -48
- package/dist/cjs/core/hooks/use-ripple.js +0 -171
- package/dist/esm/core/hooks/use-ripple.d.ts +0 -48
- package/dist/esm/core/hooks/use-ripple.js +0 -166
|
@@ -42,12 +42,12 @@ const react_1 = __importStar(require("react"));
|
|
|
42
42
|
const core_1 = require("../../core");
|
|
43
43
|
const icon_text_row_1 = require("../icon-text-row");
|
|
44
44
|
const layout_hook_1 = __importDefault(require("../../core/layout/layout.hook"));
|
|
45
|
-
const
|
|
45
|
+
const use_ripple_hook_1 = __importDefault(require("use-ripple-hook"));
|
|
46
46
|
const Button = (_a) => {
|
|
47
47
|
var { text, children, buttonType = 'filled', disabled = false, iconName, onClick, disableRipple = false, style: userStyle } = _a, rest = __rest(_a, ["text", "children", "buttonType", "disabled", "iconName", "onClick", "disableRipple", "style"]);
|
|
48
48
|
const { deviceSize } = (0, layout_hook_1.default)();
|
|
49
49
|
const theme = (0, core_1.useTheme)();
|
|
50
|
-
const [ref, createRipple] = (0,
|
|
50
|
+
const [ref, createRipple] = (0, use_ripple_hook_1.default)({ disabled: disableRipple || buttonType === 'elevated' });
|
|
51
51
|
const buttonProps = theme.buttons[buttonType];
|
|
52
52
|
const getOnColorToken = (color) => `on-${color}`;
|
|
53
53
|
const defaultContentColor = getOnColorToken(buttonProps.color);
|
|
@@ -6,18 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Card = void 0;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const core_1 = require("../../core");
|
|
9
|
-
const framer_motion_1 = require("framer-motion");
|
|
10
9
|
function Card({ children, cardType, elevation, colorToken = 'primary-container', width, height, borderRadius, }) {
|
|
11
10
|
const { colors, containers } = (0, core_1.useTheme)();
|
|
12
11
|
const { borderRadii } = containers.card;
|
|
13
12
|
const style = Object.assign({ height,
|
|
14
|
-
width,
|
|
13
|
+
width, backgroundColor: colors[colorToken || 'surface'], color: colors[`on-${colorToken}` || 'on-surface'] }, (0, core_1.Padding)('md', 'all'));
|
|
15
14
|
if (cardType === 'elevated') {
|
|
16
15
|
style.boxShadow = (0, core_1.BoxShadow)(elevation || 'raised');
|
|
17
16
|
}
|
|
18
17
|
if (borderRadii && borderRadius !== 'none') {
|
|
19
18
|
style.borderRadius = borderRadii[borderRadius || 'md'];
|
|
20
19
|
}
|
|
21
|
-
return
|
|
20
|
+
return react_1.default.createElement("div", { style: style }, children);
|
|
22
21
|
}
|
|
23
22
|
exports.Card = Card;
|
|
@@ -7,6 +7,7 @@ exports.Modal = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const card_1 = require("../card");
|
|
9
9
|
const core_1 = require("../../core");
|
|
10
|
+
const framer_motion_1 = require("framer-motion");
|
|
10
11
|
const ModalSizes = {
|
|
11
12
|
sm: 260,
|
|
12
13
|
md: 320,
|
|
@@ -15,6 +16,7 @@ const ModalSizes = {
|
|
|
15
16
|
const Modal = ({ children, isOpen, size = 'lg' }) => {
|
|
16
17
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
17
18
|
react_1.default.createElement(core_1.Overlay, { isOpen: isOpen },
|
|
18
|
-
react_1.default.createElement(
|
|
19
|
+
react_1.default.createElement(framer_motion_1.motion.div, { style: { position: 'fixed' }, initial: { y: 36, opacity: 0 }, animate: { y: 0, opacity: 1 }, exit: { y: 36, opacity: 0 }, transition: { duration: 0.2 } },
|
|
20
|
+
react_1.default.createElement(card_1.Card, { colorToken: "background", width: ModalSizes[size], cardType: "elevated", elevation: "modal" }, children)))));
|
|
19
21
|
};
|
|
20
22
|
exports.Modal = Modal;
|
|
@@ -15,5 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./use-toggle"), exports);
|
|
18
|
-
__exportStar(require("./use-ripple"), exports);
|
|
19
18
|
__exportStar(require("./use-media"), exports);
|
|
@@ -13,7 +13,7 @@ import React, { useEffect, useState } from 'react';
|
|
|
13
13
|
import { BoxShadow, Text, useTheme } from '../../core';
|
|
14
14
|
import { IconTextRow } from '../icon-text-row';
|
|
15
15
|
import useLayout from '../../core/layout/layout.hook';
|
|
16
|
-
import useRipple from '
|
|
16
|
+
import useRipple from 'use-ripple-hook';
|
|
17
17
|
export const Button = (_a) => {
|
|
18
18
|
var { text, children, buttonType = 'filled', disabled = false, iconName, onClick, disableRipple = false, style: userStyle } = _a, rest = __rest(_a, ["text", "children", "buttonType", "disabled", "iconName", "onClick", "disableRipple", "style"]);
|
|
19
19
|
const { deviceSize } = useLayout();
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { BoxShadow, Padding, useTheme } from '../../core';
|
|
3
|
-
import { motion } from 'framer-motion';
|
|
4
3
|
export function Card({ children, cardType, elevation, colorToken = 'primary-container', width, height, borderRadius, }) {
|
|
5
4
|
const { colors, containers } = useTheme();
|
|
6
5
|
const { borderRadii } = containers.card;
|
|
7
6
|
const style = Object.assign({ height,
|
|
8
|
-
width,
|
|
7
|
+
width, backgroundColor: colors[colorToken || 'surface'], color: colors[`on-${colorToken}` || 'on-surface'] }, Padding('md', 'all'));
|
|
9
8
|
if (cardType === 'elevated') {
|
|
10
9
|
style.boxShadow = BoxShadow(elevation || 'raised');
|
|
11
10
|
}
|
|
12
11
|
if (borderRadii && borderRadius !== 'none') {
|
|
13
12
|
style.borderRadius = borderRadii[borderRadius || 'md'];
|
|
14
13
|
}
|
|
15
|
-
return
|
|
14
|
+
return React.createElement("div", { style: style }, children);
|
|
16
15
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Card } from '../card';
|
|
3
3
|
import { Overlay } from '../../core';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
4
5
|
const ModalSizes = {
|
|
5
6
|
sm: 260,
|
|
6
7
|
md: 320,
|
|
@@ -9,5 +10,6 @@ const ModalSizes = {
|
|
|
9
10
|
export const Modal = ({ children, isOpen, size = 'lg' }) => {
|
|
10
11
|
return (React.createElement(React.Fragment, null,
|
|
11
12
|
React.createElement(Overlay, { isOpen: isOpen },
|
|
12
|
-
React.createElement(
|
|
13
|
+
React.createElement(motion.div, { style: { position: 'fixed' }, initial: { y: 36, opacity: 0 }, animate: { y: 0, opacity: 1 }, exit: { y: 36, opacity: 0 }, transition: { duration: 0.2 } },
|
|
14
|
+
React.createElement(Card, { colorToken: "background", width: ModalSizes[size], cardType: "elevated", elevation: "modal" }, children)))));
|
|
13
15
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uni-design-system/uni-react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "React component library for the UNI Design System.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -37,8 +37,9 @@
|
|
|
37
37
|
"@dnd-kit/modifiers": "^6.0.1",
|
|
38
38
|
"@dnd-kit/sortable": "^7.0.2",
|
|
39
39
|
"@uni-design-system/uni-core": "^0.0.33",
|
|
40
|
-
"@uni-design-system/uni-react-icons": "^0.1.
|
|
41
|
-
"framer-motion": "4.1.17"
|
|
40
|
+
"@uni-design-system/uni-react-icons": "^0.1.2",
|
|
41
|
+
"framer-motion": "4.1.17",
|
|
42
|
+
"use-ripple-hook": "^1.0.22"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"@babel/core": "^7.17.5",
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
export type Options<T extends HTMLElement = any> = {
|
|
3
|
-
duration: number;
|
|
4
|
-
color: string;
|
|
5
|
-
timingFunction: string;
|
|
6
|
-
disabled?: boolean;
|
|
7
|
-
className: string;
|
|
8
|
-
containerClassName: string;
|
|
9
|
-
ignoreNonLeftClick: boolean;
|
|
10
|
-
onSpawn?: (ctx: {
|
|
11
|
-
/** the ripple element */
|
|
12
|
-
readonly ripple: HTMLDivElement;
|
|
13
|
-
/** cancels the current ripple animation */
|
|
14
|
-
readonly cancelRipple: () => void;
|
|
15
|
-
/** the ref to the ripple host element */
|
|
16
|
-
readonly ref: React.RefObject<T>;
|
|
17
|
-
/** the event that triggered the ripple (ts: casting required) */
|
|
18
|
-
readonly event: unknown;
|
|
19
|
-
/** the ripple container element */
|
|
20
|
-
readonly container: HTMLDivElement;
|
|
21
|
-
}) => void;
|
|
22
|
-
cancelAutomatically: boolean;
|
|
23
|
-
ref: React.RefObject<T>;
|
|
24
|
-
};
|
|
25
|
-
export type MinimalEvent = {
|
|
26
|
-
clientX: number;
|
|
27
|
-
clientY: number;
|
|
28
|
-
nativeEvent?: {
|
|
29
|
-
which?: number;
|
|
30
|
-
type?: string;
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* useRipple - Material UI style ripple effect React hook
|
|
35
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
36
|
-
* @param inputOptions Ripple options
|
|
37
|
-
* @returns Tuple `[ref, event]`. See https://github.com/asplunds/use-ripple for usage
|
|
38
|
-
*/
|
|
39
|
-
export default function useRipple<T extends HTMLElement = any>(inputOptions?: Partial<Options<T>>): readonly [import("react").RefObject<any>, (event: MinimalEvent) => void];
|
|
40
|
-
/**
|
|
41
|
-
* HOF useRipple - Generate a custom ripple hook with predefined options
|
|
42
|
-
*
|
|
43
|
-
* After generating a HOF useRipple you can then override some or all predefined options by passing a new option object.
|
|
44
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
45
|
-
* @param inputOptions ripple options
|
|
46
|
-
* @returns Custom HOC useRipple hook
|
|
47
|
-
*/
|
|
48
|
-
export declare function customRipple<T extends HTMLElement = any>(inputOptions?: Partial<Omit<Options<T>, 'ref'>>): (overrideOptions?: Partial<Options<T>>) => readonly [import("react").RefObject<any>, (event: MinimalEvent) => void];
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// https://github.com/asplunds/use-ripple
|
|
3
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
4
|
-
var t = {};
|
|
5
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
6
|
-
t[p] = s[p];
|
|
7
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
8
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
9
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
10
|
-
t[p[i]] = s[p[i]];
|
|
11
|
-
}
|
|
12
|
-
return t;
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.customRipple = void 0;
|
|
16
|
-
const react_1 = require("react");
|
|
17
|
-
const self = () => document;
|
|
18
|
-
const completedFactor = 0.4;
|
|
19
|
-
const className = '__useRipple--ripple';
|
|
20
|
-
const containerClassName = '__useRipple--ripple-container';
|
|
21
|
-
/**
|
|
22
|
-
* useRipple - Material UI style ripple effect React hook
|
|
23
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
24
|
-
* @param inputOptions Ripple options
|
|
25
|
-
* @returns Tuple `[ref, event]`. See https://github.com/asplunds/use-ripple for usage
|
|
26
|
-
*/
|
|
27
|
-
function useRipple(inputOptions) {
|
|
28
|
-
const internalRef = (0, react_1.useRef)(null);
|
|
29
|
-
const _a = Object.assign({ duration: 450, color: 'rgba(255, 255, 255, .3)', cancelAutomatically: false, timingFunction: 'cubic-bezier(.42,.36,.28,.88)', disabled: false, className,
|
|
30
|
-
containerClassName, ignoreNonLeftClick: true, ref: internalRef }, (inputOptions !== null && inputOptions !== void 0 ? inputOptions : {})), { ref } = _a, options = __rest(_a, ["ref"]);
|
|
31
|
-
const event = (0, react_1.useCallback)((event) => {
|
|
32
|
-
var _a, _b;
|
|
33
|
-
if (!ref.current ||
|
|
34
|
-
options.disabled ||
|
|
35
|
-
(options.ignoreNonLeftClick && ((_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.which) !== 1 && ((_b = event.nativeEvent) === null || _b === void 0 ? void 0 : _b.type) === 'mousedown'))
|
|
36
|
-
return;
|
|
37
|
-
const target = ref.current;
|
|
38
|
-
if (window.getComputedStyle(target).position === 'static')
|
|
39
|
-
void applyStyles([['position', 'relative']], target);
|
|
40
|
-
if (!target)
|
|
41
|
-
return;
|
|
42
|
-
const existingContainer = target.querySelector(`:scope > .${options.containerClassName}`);
|
|
43
|
-
const container = existingContainer !== null && existingContainer !== void 0 ? existingContainer : createRippleContainer(options.containerClassName);
|
|
44
|
-
if (!existingContainer)
|
|
45
|
-
target.appendChild(container);
|
|
46
|
-
// Used to ensure overflow: hidden is registered properly on IOS Safari before ripple is shown
|
|
47
|
-
void requestAnimationFrame(() => {
|
|
48
|
-
var _a;
|
|
49
|
-
const begun = Date.now();
|
|
50
|
-
const ripple = centerElementToPointer(event, target, createRipple(target, event, options));
|
|
51
|
-
const events = ['mouseup', 'touchend'];
|
|
52
|
-
const cancelRipple = () => {
|
|
53
|
-
const now = Date.now();
|
|
54
|
-
const diff = now - begun;
|
|
55
|
-
// Ensure the transform animation is complete before cancellation
|
|
56
|
-
void setTimeout(() => {
|
|
57
|
-
void cancelRippleAnimation(ripple, options);
|
|
58
|
-
}, diff > 0.4 * options.duration ? 0 : completedFactor * options.duration - diff);
|
|
59
|
-
for (const event of events)
|
|
60
|
-
void self().removeEventListener(event, cancelRipple);
|
|
61
|
-
};
|
|
62
|
-
if (!options.cancelAutomatically && !isTouchDevice())
|
|
63
|
-
for (const event of events)
|
|
64
|
-
void self().addEventListener(event, cancelRipple);
|
|
65
|
-
else
|
|
66
|
-
setTimeout(() => void cancelRippleAnimation(ripple, options), options.duration * completedFactor);
|
|
67
|
-
void container.appendChild(ripple);
|
|
68
|
-
void ((_a = options.onSpawn) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
69
|
-
ripple,
|
|
70
|
-
cancelRipple,
|
|
71
|
-
event,
|
|
72
|
-
ref,
|
|
73
|
-
container,
|
|
74
|
-
}));
|
|
75
|
-
});
|
|
76
|
-
}, [ref, options]);
|
|
77
|
-
return [ref, event];
|
|
78
|
-
}
|
|
79
|
-
exports.default = useRipple;
|
|
80
|
-
/**
|
|
81
|
-
* HOF useRipple - Generate a custom ripple hook with predefined options
|
|
82
|
-
*
|
|
83
|
-
* After generating a HOF useRipple you can then override some or all predefined options by passing a new option object.
|
|
84
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
85
|
-
* @param inputOptions ripple options
|
|
86
|
-
* @returns Custom HOC useRipple hook
|
|
87
|
-
*/
|
|
88
|
-
function customRipple(inputOptions) {
|
|
89
|
-
return (overrideOptions) => useRipple(Object.assign(Object.assign({}, inputOptions), overrideOptions));
|
|
90
|
-
}
|
|
91
|
-
exports.customRipple = customRipple;
|
|
92
|
-
function centerElementToPointer(event, ref, element) {
|
|
93
|
-
const { top, left } = ref.getBoundingClientRect();
|
|
94
|
-
void element.style.setProperty('top', px(event.clientY - top));
|
|
95
|
-
void element.style.setProperty('left', px(event.clientX - left));
|
|
96
|
-
return element;
|
|
97
|
-
}
|
|
98
|
-
function px(arg) {
|
|
99
|
-
return `${arg}px`;
|
|
100
|
-
}
|
|
101
|
-
function createRipple(ref, event, { duration, color, timingFunction, className }, ctx = document) {
|
|
102
|
-
const element = ctx.createElement('div');
|
|
103
|
-
const { clientX, clientY } = event;
|
|
104
|
-
const { height, width, top, left } = ref.getBoundingClientRect();
|
|
105
|
-
const maxHeight = Math.max(clientY - top, height - clientY + top);
|
|
106
|
-
const maxWidth = Math.max(clientX - left, width - clientX + left);
|
|
107
|
-
// @ts-ignore
|
|
108
|
-
const size = px(Math.hypot(maxHeight, maxWidth) * 2);
|
|
109
|
-
const styles = [
|
|
110
|
-
['position', 'absolute'],
|
|
111
|
-
['height', size],
|
|
112
|
-
['width', size],
|
|
113
|
-
['transform', 'translate(-50%, -50%) scale(0)'],
|
|
114
|
-
['pointer-events', 'none'],
|
|
115
|
-
['border-radius', '50%'],
|
|
116
|
-
['opacity', '.6'],
|
|
117
|
-
['background', color],
|
|
118
|
-
[
|
|
119
|
-
'transition',
|
|
120
|
-
`transform ${duration * 0.6}ms ${timingFunction}, opacity ${Math.max(duration * 0.05, 140)}ms ease-out`,
|
|
121
|
-
],
|
|
122
|
-
];
|
|
123
|
-
void element.classList.add(className);
|
|
124
|
-
void window.requestAnimationFrame(() => {
|
|
125
|
-
void applyStyles([['transform', 'translate(-50%, -50%) scale(1)']], element);
|
|
126
|
-
});
|
|
127
|
-
return applyStyles(styles, element);
|
|
128
|
-
}
|
|
129
|
-
function applyStyles(styles, target) {
|
|
130
|
-
if (!target)
|
|
131
|
-
return target;
|
|
132
|
-
for (const [property, value] of styles) {
|
|
133
|
-
void target.style.setProperty(property, value);
|
|
134
|
-
}
|
|
135
|
-
return target;
|
|
136
|
-
}
|
|
137
|
-
function cancelRippleAnimation(element, options) {
|
|
138
|
-
const { duration, timingFunction } = options;
|
|
139
|
-
void applyStyles([
|
|
140
|
-
['opacity', '0'],
|
|
141
|
-
[
|
|
142
|
-
'transition',
|
|
143
|
-
`transform ${duration * 0.6}ms ${timingFunction}, opacity ${duration * 0.65}ms ease-in-out ${duration * 0.13}ms`,
|
|
144
|
-
],
|
|
145
|
-
], element);
|
|
146
|
-
void window.requestAnimationFrame(() => {
|
|
147
|
-
void element.addEventListener('transitionend', (e) => {
|
|
148
|
-
if (e.propertyName === 'opacity')
|
|
149
|
-
void element.remove();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
function createRippleContainer(className) {
|
|
154
|
-
const container = self().createElement('div');
|
|
155
|
-
void container.classList.add(className);
|
|
156
|
-
return applyStyles([
|
|
157
|
-
['position', 'absolute'],
|
|
158
|
-
['height', '100%'],
|
|
159
|
-
['width', '100%'],
|
|
160
|
-
['border-radius', 'inherit'],
|
|
161
|
-
['top', '0'],
|
|
162
|
-
['left', '0'],
|
|
163
|
-
['pointer-events', 'none'],
|
|
164
|
-
['overflow', 'hidden'],
|
|
165
|
-
], container);
|
|
166
|
-
}
|
|
167
|
-
/** taken from https://stackoverflow.com/a/4819886/13188385 */
|
|
168
|
-
function isTouchDevice() {
|
|
169
|
-
var _a;
|
|
170
|
-
return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.msMaxTouchPoints) !== null && _a !== void 0 ? _a : 0 > 0);
|
|
171
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
export type Options<T extends HTMLElement = any> = {
|
|
3
|
-
duration: number;
|
|
4
|
-
color: string;
|
|
5
|
-
timingFunction: string;
|
|
6
|
-
disabled?: boolean;
|
|
7
|
-
className: string;
|
|
8
|
-
containerClassName: string;
|
|
9
|
-
ignoreNonLeftClick: boolean;
|
|
10
|
-
onSpawn?: (ctx: {
|
|
11
|
-
/** the ripple element */
|
|
12
|
-
readonly ripple: HTMLDivElement;
|
|
13
|
-
/** cancels the current ripple animation */
|
|
14
|
-
readonly cancelRipple: () => void;
|
|
15
|
-
/** the ref to the ripple host element */
|
|
16
|
-
readonly ref: React.RefObject<T>;
|
|
17
|
-
/** the event that triggered the ripple (ts: casting required) */
|
|
18
|
-
readonly event: unknown;
|
|
19
|
-
/** the ripple container element */
|
|
20
|
-
readonly container: HTMLDivElement;
|
|
21
|
-
}) => void;
|
|
22
|
-
cancelAutomatically: boolean;
|
|
23
|
-
ref: React.RefObject<T>;
|
|
24
|
-
};
|
|
25
|
-
export type MinimalEvent = {
|
|
26
|
-
clientX: number;
|
|
27
|
-
clientY: number;
|
|
28
|
-
nativeEvent?: {
|
|
29
|
-
which?: number;
|
|
30
|
-
type?: string;
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* useRipple - Material UI style ripple effect React hook
|
|
35
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
36
|
-
* @param inputOptions Ripple options
|
|
37
|
-
* @returns Tuple `[ref, event]`. See https://github.com/asplunds/use-ripple for usage
|
|
38
|
-
*/
|
|
39
|
-
export default function useRipple<T extends HTMLElement = any>(inputOptions?: Partial<Options<T>>): readonly [import("react").RefObject<any>, (event: MinimalEvent) => void];
|
|
40
|
-
/**
|
|
41
|
-
* HOF useRipple - Generate a custom ripple hook with predefined options
|
|
42
|
-
*
|
|
43
|
-
* After generating a HOF useRipple you can then override some or all predefined options by passing a new option object.
|
|
44
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
45
|
-
* @param inputOptions ripple options
|
|
46
|
-
* @returns Custom HOC useRipple hook
|
|
47
|
-
*/
|
|
48
|
-
export declare function customRipple<T extends HTMLElement = any>(inputOptions?: Partial<Omit<Options<T>, 'ref'>>): (overrideOptions?: Partial<Options<T>>) => readonly [import("react").RefObject<any>, (event: MinimalEvent) => void];
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
// https://github.com/asplunds/use-ripple
|
|
2
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
-
var t = {};
|
|
4
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
-
t[p] = s[p];
|
|
6
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
-
t[p[i]] = s[p[i]];
|
|
10
|
-
}
|
|
11
|
-
return t;
|
|
12
|
-
};
|
|
13
|
-
import { useCallback, useRef } from 'react';
|
|
14
|
-
const self = () => document;
|
|
15
|
-
const completedFactor = 0.4;
|
|
16
|
-
const className = '__useRipple--ripple';
|
|
17
|
-
const containerClassName = '__useRipple--ripple-container';
|
|
18
|
-
/**
|
|
19
|
-
* useRipple - Material UI style ripple effect React hook
|
|
20
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
21
|
-
* @param inputOptions Ripple options
|
|
22
|
-
* @returns Tuple `[ref, event]`. See https://github.com/asplunds/use-ripple for usage
|
|
23
|
-
*/
|
|
24
|
-
export default function useRipple(inputOptions) {
|
|
25
|
-
const internalRef = useRef(null);
|
|
26
|
-
const _a = Object.assign({ duration: 450, color: 'rgba(255, 255, 255, .3)', cancelAutomatically: false, timingFunction: 'cubic-bezier(.42,.36,.28,.88)', disabled: false, className,
|
|
27
|
-
containerClassName, ignoreNonLeftClick: true, ref: internalRef }, (inputOptions !== null && inputOptions !== void 0 ? inputOptions : {})), { ref } = _a, options = __rest(_a, ["ref"]);
|
|
28
|
-
const event = useCallback((event) => {
|
|
29
|
-
var _a, _b;
|
|
30
|
-
if (!ref.current ||
|
|
31
|
-
options.disabled ||
|
|
32
|
-
(options.ignoreNonLeftClick && ((_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.which) !== 1 && ((_b = event.nativeEvent) === null || _b === void 0 ? void 0 : _b.type) === 'mousedown'))
|
|
33
|
-
return;
|
|
34
|
-
const target = ref.current;
|
|
35
|
-
if (window.getComputedStyle(target).position === 'static')
|
|
36
|
-
void applyStyles([['position', 'relative']], target);
|
|
37
|
-
if (!target)
|
|
38
|
-
return;
|
|
39
|
-
const existingContainer = target.querySelector(`:scope > .${options.containerClassName}`);
|
|
40
|
-
const container = existingContainer !== null && existingContainer !== void 0 ? existingContainer : createRippleContainer(options.containerClassName);
|
|
41
|
-
if (!existingContainer)
|
|
42
|
-
target.appendChild(container);
|
|
43
|
-
// Used to ensure overflow: hidden is registered properly on IOS Safari before ripple is shown
|
|
44
|
-
void requestAnimationFrame(() => {
|
|
45
|
-
var _a;
|
|
46
|
-
const begun = Date.now();
|
|
47
|
-
const ripple = centerElementToPointer(event, target, createRipple(target, event, options));
|
|
48
|
-
const events = ['mouseup', 'touchend'];
|
|
49
|
-
const cancelRipple = () => {
|
|
50
|
-
const now = Date.now();
|
|
51
|
-
const diff = now - begun;
|
|
52
|
-
// Ensure the transform animation is complete before cancellation
|
|
53
|
-
void setTimeout(() => {
|
|
54
|
-
void cancelRippleAnimation(ripple, options);
|
|
55
|
-
}, diff > 0.4 * options.duration ? 0 : completedFactor * options.duration - diff);
|
|
56
|
-
for (const event of events)
|
|
57
|
-
void self().removeEventListener(event, cancelRipple);
|
|
58
|
-
};
|
|
59
|
-
if (!options.cancelAutomatically && !isTouchDevice())
|
|
60
|
-
for (const event of events)
|
|
61
|
-
void self().addEventListener(event, cancelRipple);
|
|
62
|
-
else
|
|
63
|
-
setTimeout(() => void cancelRippleAnimation(ripple, options), options.duration * completedFactor);
|
|
64
|
-
void container.appendChild(ripple);
|
|
65
|
-
void ((_a = options.onSpawn) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
66
|
-
ripple,
|
|
67
|
-
cancelRipple,
|
|
68
|
-
event,
|
|
69
|
-
ref,
|
|
70
|
-
container,
|
|
71
|
-
}));
|
|
72
|
-
});
|
|
73
|
-
}, [ref, options]);
|
|
74
|
-
return [ref, event];
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* HOF useRipple - Generate a custom ripple hook with predefined options
|
|
78
|
-
*
|
|
79
|
-
* After generating a HOF useRipple you can then override some or all predefined options by passing a new option object.
|
|
80
|
-
* @author Jonathan Asplund <jonathan@asplund.net>
|
|
81
|
-
* @param inputOptions ripple options
|
|
82
|
-
* @returns Custom HOC useRipple hook
|
|
83
|
-
*/
|
|
84
|
-
export function customRipple(inputOptions) {
|
|
85
|
-
return (overrideOptions) => useRipple(Object.assign(Object.assign({}, inputOptions), overrideOptions));
|
|
86
|
-
}
|
|
87
|
-
function centerElementToPointer(event, ref, element) {
|
|
88
|
-
const { top, left } = ref.getBoundingClientRect();
|
|
89
|
-
void element.style.setProperty('top', px(event.clientY - top));
|
|
90
|
-
void element.style.setProperty('left', px(event.clientX - left));
|
|
91
|
-
return element;
|
|
92
|
-
}
|
|
93
|
-
function px(arg) {
|
|
94
|
-
return `${arg}px`;
|
|
95
|
-
}
|
|
96
|
-
function createRipple(ref, event, { duration, color, timingFunction, className }, ctx = document) {
|
|
97
|
-
const element = ctx.createElement('div');
|
|
98
|
-
const { clientX, clientY } = event;
|
|
99
|
-
const { height, width, top, left } = ref.getBoundingClientRect();
|
|
100
|
-
const maxHeight = Math.max(clientY - top, height - clientY + top);
|
|
101
|
-
const maxWidth = Math.max(clientX - left, width - clientX + left);
|
|
102
|
-
// @ts-ignore
|
|
103
|
-
const size = px(Math.hypot(maxHeight, maxWidth) * 2);
|
|
104
|
-
const styles = [
|
|
105
|
-
['position', 'absolute'],
|
|
106
|
-
['height', size],
|
|
107
|
-
['width', size],
|
|
108
|
-
['transform', 'translate(-50%, -50%) scale(0)'],
|
|
109
|
-
['pointer-events', 'none'],
|
|
110
|
-
['border-radius', '50%'],
|
|
111
|
-
['opacity', '.6'],
|
|
112
|
-
['background', color],
|
|
113
|
-
[
|
|
114
|
-
'transition',
|
|
115
|
-
`transform ${duration * 0.6}ms ${timingFunction}, opacity ${Math.max(duration * 0.05, 140)}ms ease-out`,
|
|
116
|
-
],
|
|
117
|
-
];
|
|
118
|
-
void element.classList.add(className);
|
|
119
|
-
void window.requestAnimationFrame(() => {
|
|
120
|
-
void applyStyles([['transform', 'translate(-50%, -50%) scale(1)']], element);
|
|
121
|
-
});
|
|
122
|
-
return applyStyles(styles, element);
|
|
123
|
-
}
|
|
124
|
-
function applyStyles(styles, target) {
|
|
125
|
-
if (!target)
|
|
126
|
-
return target;
|
|
127
|
-
for (const [property, value] of styles) {
|
|
128
|
-
void target.style.setProperty(property, value);
|
|
129
|
-
}
|
|
130
|
-
return target;
|
|
131
|
-
}
|
|
132
|
-
function cancelRippleAnimation(element, options) {
|
|
133
|
-
const { duration, timingFunction } = options;
|
|
134
|
-
void applyStyles([
|
|
135
|
-
['opacity', '0'],
|
|
136
|
-
[
|
|
137
|
-
'transition',
|
|
138
|
-
`transform ${duration * 0.6}ms ${timingFunction}, opacity ${duration * 0.65}ms ease-in-out ${duration * 0.13}ms`,
|
|
139
|
-
],
|
|
140
|
-
], element);
|
|
141
|
-
void window.requestAnimationFrame(() => {
|
|
142
|
-
void element.addEventListener('transitionend', (e) => {
|
|
143
|
-
if (e.propertyName === 'opacity')
|
|
144
|
-
void element.remove();
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
function createRippleContainer(className) {
|
|
149
|
-
const container = self().createElement('div');
|
|
150
|
-
void container.classList.add(className);
|
|
151
|
-
return applyStyles([
|
|
152
|
-
['position', 'absolute'],
|
|
153
|
-
['height', '100%'],
|
|
154
|
-
['width', '100%'],
|
|
155
|
-
['border-radius', 'inherit'],
|
|
156
|
-
['top', '0'],
|
|
157
|
-
['left', '0'],
|
|
158
|
-
['pointer-events', 'none'],
|
|
159
|
-
['overflow', 'hidden'],
|
|
160
|
-
], container);
|
|
161
|
-
}
|
|
162
|
-
/** taken from https://stackoverflow.com/a/4819886/13188385 */
|
|
163
|
-
function isTouchDevice() {
|
|
164
|
-
var _a;
|
|
165
|
-
return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.msMaxTouchPoints) !== null && _a !== void 0 ? _a : 0 > 0);
|
|
166
|
-
}
|