1 | 'use client';
|
2 |
|
3 | import * as React from 'react';
|
4 | import PropTypes from 'prop-types';
|
5 | import clsx from 'clsx';
|
6 | import refType from '@mui/utils/refType';
|
7 | import elementTypeAcceptingRef from '@mui/utils/elementTypeAcceptingRef';
|
8 | import composeClasses from '@mui/utils/composeClasses';
|
9 | import isFocusVisible from '@mui/utils/isFocusVisible';
|
10 | import { styled } from "../zero-styled/index.js";
|
11 | import { useDefaultProps } from "../DefaultPropsProvider/index.js";
|
12 | import useForkRef from "../utils/useForkRef.js";
|
13 | import useEventCallback from "../utils/useEventCallback.js";
|
14 | import useLazyRipple from "../useLazyRipple/index.js";
|
15 | import TouchRipple from "./TouchRipple.js";
|
16 | import buttonBaseClasses, { getButtonBaseUtilityClass } from "./buttonBaseClasses.js";
|
17 | import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
18 | const useUtilityClasses = ownerState => {
|
19 | const {
|
20 | disabled,
|
21 | focusVisible,
|
22 | focusVisibleClassName,
|
23 | classes
|
24 | } = ownerState;
|
25 | const slots = {
|
26 | root: ['root', disabled && 'disabled', focusVisible && 'focusVisible']
|
27 | };
|
28 | const composedClasses = composeClasses(slots, getButtonBaseUtilityClass, classes);
|
29 | if (focusVisible && focusVisibleClassName) {
|
30 | composedClasses.root += ` ${focusVisibleClassName}`;
|
31 | }
|
32 | return composedClasses;
|
33 | };
|
34 | export const ButtonBaseRoot = styled('button', {
|
35 | name: 'MuiButtonBase',
|
36 | slot: 'Root',
|
37 | overridesResolver: (props, styles) => styles.root
|
38 | })({
|
39 | display: 'inline-flex',
|
40 | alignItems: 'center',
|
41 | justifyContent: 'center',
|
42 | position: 'relative',
|
43 | boxSizing: 'border-box',
|
44 | WebkitTapHighlightColor: 'transparent',
|
45 | backgroundColor: 'transparent',
|
46 |
|
47 |
|
48 | outline: 0,
|
49 | border: 0,
|
50 | margin: 0,
|
51 |
|
52 | borderRadius: 0,
|
53 | padding: 0,
|
54 |
|
55 | cursor: 'pointer',
|
56 | userSelect: 'none',
|
57 | verticalAlign: 'middle',
|
58 | MozAppearance: 'none',
|
59 |
|
60 | WebkitAppearance: 'none',
|
61 |
|
62 | textDecoration: 'none',
|
63 |
|
64 | color: 'inherit',
|
65 | '&::-moz-focus-inner': {
|
66 | borderStyle: 'none'
|
67 | },
|
68 | [`&.${buttonBaseClasses.disabled}`]: {
|
69 | pointerEvents: 'none',
|
70 |
|
71 | cursor: 'default'
|
72 | },
|
73 | '@media print': {
|
74 | colorAdjust: 'exact'
|
75 | }
|
76 | });
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | const ButtonBase = React.forwardRef(function ButtonBase(inProps, ref) {
|
84 | const props = useDefaultProps({
|
85 | props: inProps,
|
86 | name: 'MuiButtonBase'
|
87 | });
|
88 | const {
|
89 | action,
|
90 | centerRipple = false,
|
91 | children,
|
92 | className,
|
93 | component = 'button',
|
94 | disabled = false,
|
95 | disableRipple = false,
|
96 | disableTouchRipple = false,
|
97 | focusRipple = false,
|
98 | focusVisibleClassName,
|
99 | LinkComponent = 'a',
|
100 | onBlur,
|
101 | onClick,
|
102 | onContextMenu,
|
103 | onDragLeave,
|
104 | onFocus,
|
105 | onFocusVisible,
|
106 | onKeyDown,
|
107 | onKeyUp,
|
108 | onMouseDown,
|
109 | onMouseLeave,
|
110 | onMouseUp,
|
111 | onTouchEnd,
|
112 | onTouchMove,
|
113 | onTouchStart,
|
114 | tabIndex = 0,
|
115 | TouchRippleProps,
|
116 | touchRippleRef,
|
117 | type,
|
118 | ...other
|
119 | } = props;
|
120 | const buttonRef = React.useRef(null);
|
121 | const ripple = useLazyRipple();
|
122 | const handleRippleRef = useForkRef(ripple.ref, touchRippleRef);
|
123 | const [focusVisible, setFocusVisible] = React.useState(false);
|
124 | if (disabled && focusVisible) {
|
125 | setFocusVisible(false);
|
126 | }
|
127 | React.useImperativeHandle(action, () => ({
|
128 | focusVisible: () => {
|
129 | setFocusVisible(true);
|
130 | buttonRef.current.focus();
|
131 | }
|
132 | }), []);
|
133 | const enableTouchRipple = ripple.shouldMount && !disableRipple && !disabled;
|
134 | React.useEffect(() => {
|
135 | if (focusVisible && focusRipple && !disableRipple) {
|
136 | ripple.pulsate();
|
137 | }
|
138 | }, [disableRipple, focusRipple, focusVisible, ripple]);
|
139 | const handleMouseDown = useRippleHandler(ripple, 'start', onMouseDown, disableTouchRipple);
|
140 | const handleContextMenu = useRippleHandler(ripple, 'stop', onContextMenu, disableTouchRipple);
|
141 | const handleDragLeave = useRippleHandler(ripple, 'stop', onDragLeave, disableTouchRipple);
|
142 | const handleMouseUp = useRippleHandler(ripple, 'stop', onMouseUp, disableTouchRipple);
|
143 | const handleMouseLeave = useRippleHandler(ripple, 'stop', event => {
|
144 | if (focusVisible) {
|
145 | event.preventDefault();
|
146 | }
|
147 | if (onMouseLeave) {
|
148 | onMouseLeave(event);
|
149 | }
|
150 | }, disableTouchRipple);
|
151 | const handleTouchStart = useRippleHandler(ripple, 'start', onTouchStart, disableTouchRipple);
|
152 | const handleTouchEnd = useRippleHandler(ripple, 'stop', onTouchEnd, disableTouchRipple);
|
153 | const handleTouchMove = useRippleHandler(ripple, 'stop', onTouchMove, disableTouchRipple);
|
154 | const handleBlur = useRippleHandler(ripple, 'stop', event => {
|
155 | if (!isFocusVisible(event.target)) {
|
156 | setFocusVisible(false);
|
157 | }
|
158 | if (onBlur) {
|
159 | onBlur(event);
|
160 | }
|
161 | }, false);
|
162 | const handleFocus = useEventCallback(event => {
|
163 |
|
164 | if (!buttonRef.current) {
|
165 | buttonRef.current = event.currentTarget;
|
166 | }
|
167 | if (isFocusVisible(event.target)) {
|
168 | setFocusVisible(true);
|
169 | if (onFocusVisible) {
|
170 | onFocusVisible(event);
|
171 | }
|
172 | }
|
173 | if (onFocus) {
|
174 | onFocus(event);
|
175 | }
|
176 | });
|
177 | const isNonNativeButton = () => {
|
178 | const button = buttonRef.current;
|
179 | return component && component !== 'button' && !(button.tagName === 'A' && button.href);
|
180 | };
|
181 | const handleKeyDown = useEventCallback(event => {
|
182 |
|
183 | if (focusRipple && !event.repeat && focusVisible && event.key === ' ') {
|
184 | ripple.stop(event, () => {
|
185 | ripple.start(event);
|
186 | });
|
187 | }
|
188 | if (event.target === event.currentTarget && isNonNativeButton() && event.key === ' ') {
|
189 | event.preventDefault();
|
190 | }
|
191 | if (onKeyDown) {
|
192 | onKeyDown(event);
|
193 | }
|
194 |
|
195 |
|
196 | if (event.target === event.currentTarget && isNonNativeButton() && event.key === 'Enter' && !disabled) {
|
197 | event.preventDefault();
|
198 | if (onClick) {
|
199 | onClick(event);
|
200 | }
|
201 | }
|
202 | });
|
203 | const handleKeyUp = useEventCallback(event => {
|
204 |
|
205 |
|
206 | if (focusRipple && event.key === ' ' && focusVisible && !event.defaultPrevented) {
|
207 | ripple.stop(event, () => {
|
208 | ripple.pulsate(event);
|
209 | });
|
210 | }
|
211 | if (onKeyUp) {
|
212 | onKeyUp(event);
|
213 | }
|
214 |
|
215 |
|
216 | if (onClick && event.target === event.currentTarget && isNonNativeButton() && event.key === ' ' && !event.defaultPrevented) {
|
217 | onClick(event);
|
218 | }
|
219 | });
|
220 | let ComponentProp = component;
|
221 | if (ComponentProp === 'button' && (other.href || other.to)) {
|
222 | ComponentProp = LinkComponent;
|
223 | }
|
224 | const buttonProps = {};
|
225 | if (ComponentProp === 'button') {
|
226 | buttonProps.type = type === undefined ? 'button' : type;
|
227 | buttonProps.disabled = disabled;
|
228 | } else {
|
229 | if (!other.href && !other.to) {
|
230 | buttonProps.role = 'button';
|
231 | }
|
232 | if (disabled) {
|
233 | buttonProps['aria-disabled'] = disabled;
|
234 | }
|
235 | }
|
236 | const handleRef = useForkRef(ref, buttonRef);
|
237 | const ownerState = {
|
238 | ...props,
|
239 | centerRipple,
|
240 | component,
|
241 | disabled,
|
242 | disableRipple,
|
243 | disableTouchRipple,
|
244 | focusRipple,
|
245 | tabIndex,
|
246 | focusVisible
|
247 | };
|
248 | const classes = useUtilityClasses(ownerState);
|
249 | return _jsxs(ButtonBaseRoot, {
|
250 | as: ComponentProp,
|
251 | className: clsx(classes.root, className),
|
252 | ownerState: ownerState,
|
253 | onBlur: handleBlur,
|
254 | onClick: onClick,
|
255 | onContextMenu: handleContextMenu,
|
256 | onFocus: handleFocus,
|
257 | onKeyDown: handleKeyDown,
|
258 | onKeyUp: handleKeyUp,
|
259 | onMouseDown: handleMouseDown,
|
260 | onMouseLeave: handleMouseLeave,
|
261 | onMouseUp: handleMouseUp,
|
262 | onDragLeave: handleDragLeave,
|
263 | onTouchEnd: handleTouchEnd,
|
264 | onTouchMove: handleTouchMove,
|
265 | onTouchStart: handleTouchStart,
|
266 | ref: handleRef,
|
267 | tabIndex: disabled ? -1 : tabIndex,
|
268 | type: type,
|
269 | ...buttonProps,
|
270 | ...other,
|
271 | children: [children, enableTouchRipple ? _jsx(TouchRipple, {
|
272 | ref: handleRippleRef,
|
273 | center: centerRipple,
|
274 | ...TouchRippleProps
|
275 | }) : null]
|
276 | });
|
277 | });
|
278 | function useRippleHandler(ripple, rippleAction, eventCallback, skipRippleAction = false) {
|
279 | return useEventCallback(event => {
|
280 | if (eventCallback) {
|
281 | eventCallback(event);
|
282 | }
|
283 | if (!skipRippleAction) {
|
284 | ripple[rippleAction](event);
|
285 | }
|
286 | return true;
|
287 | });
|
288 | }
|
289 | process.env.NODE_ENV !== "production" ? ButtonBase.propTypes = {
|
290 |
|
291 |
|
292 |
|
293 |
|
294 | |
295 |
|
296 |
|
297 |
|
298 | action: refType,
|
299 | |
300 |
|
301 |
|
302 |
|
303 |
|
304 | centerRipple: PropTypes.bool,
|
305 | |
306 |
|
307 |
|
308 | children: PropTypes.node,
|
309 | |
310 |
|
311 |
|
312 | classes: PropTypes.object,
|
313 | |
314 |
|
315 |
|
316 | className: PropTypes.string,
|
317 | |
318 |
|
319 |
|
320 |
|
321 | component: elementTypeAcceptingRef,
|
322 | |
323 |
|
324 |
|
325 |
|
326 | disabled: PropTypes.bool,
|
327 | |
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | disableRipple: PropTypes.bool,
|
335 | |
336 |
|
337 |
|
338 |
|
339 | disableTouchRipple: PropTypes.bool,
|
340 | |
341 |
|
342 |
|
343 |
|
344 | focusRipple: PropTypes.bool,
|
345 | |
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 | focusVisibleClassName: PropTypes.string,
|
354 | |
355 |
|
356 |
|
357 | href: PropTypes .any,
|
358 | |
359 |
|
360 |
|
361 |
|
362 | LinkComponent: PropTypes.elementType,
|
363 | |
364 |
|
365 |
|
366 | onBlur: PropTypes.func,
|
367 | |
368 |
|
369 |
|
370 | onClick: PropTypes.func,
|
371 | |
372 |
|
373 |
|
374 | onContextMenu: PropTypes.func,
|
375 | |
376 |
|
377 |
|
378 | onDragLeave: PropTypes.func,
|
379 | |
380 |
|
381 |
|
382 | onFocus: PropTypes.func,
|
383 | |
384 |
|
385 |
|
386 |
|
387 | onFocusVisible: PropTypes.func,
|
388 | |
389 |
|
390 |
|
391 | onKeyDown: PropTypes.func,
|
392 | |
393 |
|
394 |
|
395 | onKeyUp: PropTypes.func,
|
396 | |
397 |
|
398 |
|
399 | onMouseDown: PropTypes.func,
|
400 | |
401 |
|
402 |
|
403 | onMouseLeave: PropTypes.func,
|
404 | |
405 |
|
406 |
|
407 | onMouseUp: PropTypes.func,
|
408 | |
409 |
|
410 |
|
411 | onTouchEnd: PropTypes.func,
|
412 | |
413 |
|
414 |
|
415 | onTouchMove: PropTypes.func,
|
416 | |
417 |
|
418 |
|
419 | onTouchStart: PropTypes.func,
|
420 | |
421 |
|
422 |
|
423 | sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
|
424 | |
425 |
|
426 |
|
427 | tabIndex: PropTypes.number,
|
428 | |
429 |
|
430 |
|
431 | TouchRippleProps: PropTypes.object,
|
432 | |
433 |
|
434 |
|
435 | touchRippleRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
|
436 | current: PropTypes.shape({
|
437 | pulsate: PropTypes.func.isRequired,
|
438 | start: PropTypes.func.isRequired,
|
439 | stop: PropTypes.func.isRequired
|
440 | })
|
441 | })]),
|
442 | |
443 |
|
444 |
|
445 | type: PropTypes.oneOfType([PropTypes.oneOf(['button', 'reset', 'submit']), PropTypes.string])
|
446 | } : void 0;
|
447 | export default ButtonBase; |
\ | No newline at end of file |