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 | function useRippleHandler(rippleAction, eventCallback, skipRippleAction = disableTouchRipple) {
|
140 | return useEventCallback(event => {
|
141 | if (eventCallback) {
|
142 | eventCallback(event);
|
143 | }
|
144 | const ignore = skipRippleAction;
|
145 | if (!ignore) {
|
146 | ripple[rippleAction](event);
|
147 | }
|
148 | return true;
|
149 | });
|
150 | }
|
151 | const handleMouseDown = useRippleHandler('start', onMouseDown);
|
152 | const handleContextMenu = useRippleHandler('stop', onContextMenu);
|
153 | const handleDragLeave = useRippleHandler('stop', onDragLeave);
|
154 | const handleMouseUp = useRippleHandler('stop', onMouseUp);
|
155 | const handleMouseLeave = useRippleHandler('stop', event => {
|
156 | if (focusVisible) {
|
157 | event.preventDefault();
|
158 | }
|
159 | if (onMouseLeave) {
|
160 | onMouseLeave(event);
|
161 | }
|
162 | });
|
163 | const handleTouchStart = useRippleHandler('start', onTouchStart);
|
164 | const handleTouchEnd = useRippleHandler('stop', onTouchEnd);
|
165 | const handleTouchMove = useRippleHandler('stop', onTouchMove);
|
166 | const handleBlur = useRippleHandler('stop', event => {
|
167 | if (!isFocusVisible(event.target)) {
|
168 | setFocusVisible(false);
|
169 | }
|
170 | if (onBlur) {
|
171 | onBlur(event);
|
172 | }
|
173 | }, false);
|
174 | const handleFocus = useEventCallback(event => {
|
175 |
|
176 | if (!buttonRef.current) {
|
177 | buttonRef.current = event.currentTarget;
|
178 | }
|
179 | if (isFocusVisible(event.target)) {
|
180 | setFocusVisible(true);
|
181 | if (onFocusVisible) {
|
182 | onFocusVisible(event);
|
183 | }
|
184 | }
|
185 | if (onFocus) {
|
186 | onFocus(event);
|
187 | }
|
188 | });
|
189 | const isNonNativeButton = () => {
|
190 | const button = buttonRef.current;
|
191 | return component && component !== 'button' && !(button.tagName === 'A' && button.href);
|
192 | };
|
193 | const handleKeyDown = useEventCallback(event => {
|
194 |
|
195 | if (focusRipple && !event.repeat && focusVisible && event.key === ' ') {
|
196 | ripple.stop(event, () => {
|
197 | ripple.start(event);
|
198 | });
|
199 | }
|
200 | if (event.target === event.currentTarget && isNonNativeButton() && event.key === ' ') {
|
201 | event.preventDefault();
|
202 | }
|
203 | if (onKeyDown) {
|
204 | onKeyDown(event);
|
205 | }
|
206 |
|
207 |
|
208 | if (event.target === event.currentTarget && isNonNativeButton() && event.key === 'Enter' && !disabled) {
|
209 | event.preventDefault();
|
210 | if (onClick) {
|
211 | onClick(event);
|
212 | }
|
213 | }
|
214 | });
|
215 | const handleKeyUp = useEventCallback(event => {
|
216 |
|
217 |
|
218 | if (focusRipple && event.key === ' ' && focusVisible && !event.defaultPrevented) {
|
219 | ripple.stop(event, () => {
|
220 | ripple.pulsate(event);
|
221 | });
|
222 | }
|
223 | if (onKeyUp) {
|
224 | onKeyUp(event);
|
225 | }
|
226 |
|
227 |
|
228 | if (onClick && event.target === event.currentTarget && isNonNativeButton() && event.key === ' ' && !event.defaultPrevented) {
|
229 | onClick(event);
|
230 | }
|
231 | });
|
232 | let ComponentProp = component;
|
233 | if (ComponentProp === 'button' && (other.href || other.to)) {
|
234 | ComponentProp = LinkComponent;
|
235 | }
|
236 | const buttonProps = {};
|
237 | if (ComponentProp === 'button') {
|
238 | buttonProps.type = type === undefined ? 'button' : type;
|
239 | buttonProps.disabled = disabled;
|
240 | } else {
|
241 | if (!other.href && !other.to) {
|
242 | buttonProps.role = 'button';
|
243 | }
|
244 | if (disabled) {
|
245 | buttonProps['aria-disabled'] = disabled;
|
246 | }
|
247 | }
|
248 | const handleRef = useForkRef(ref, buttonRef);
|
249 | const ownerState = {
|
250 | ...props,
|
251 | centerRipple,
|
252 | component,
|
253 | disabled,
|
254 | disableRipple,
|
255 | disableTouchRipple,
|
256 | focusRipple,
|
257 | tabIndex,
|
258 | focusVisible
|
259 | };
|
260 | const classes = useUtilityClasses(ownerState);
|
261 | return _jsxs(ButtonBaseRoot, {
|
262 | as: ComponentProp,
|
263 | className: clsx(classes.root, className),
|
264 | ownerState: ownerState,
|
265 | onBlur: handleBlur,
|
266 | onClick: onClick,
|
267 | onContextMenu: handleContextMenu,
|
268 | onFocus: handleFocus,
|
269 | onKeyDown: handleKeyDown,
|
270 | onKeyUp: handleKeyUp,
|
271 | onMouseDown: handleMouseDown,
|
272 | onMouseLeave: handleMouseLeave,
|
273 | onMouseUp: handleMouseUp,
|
274 | onDragLeave: handleDragLeave,
|
275 | onTouchEnd: handleTouchEnd,
|
276 | onTouchMove: handleTouchMove,
|
277 | onTouchStart: handleTouchStart,
|
278 | ref: handleRef,
|
279 | tabIndex: disabled ? -1 : tabIndex,
|
280 | type: type,
|
281 | ...buttonProps,
|
282 | ...other,
|
283 | children: [children, enableTouchRipple ? _jsx(TouchRipple, {
|
284 | ref: handleRippleRef,
|
285 | center: centerRipple,
|
286 | ...TouchRippleProps
|
287 | }) : null]
|
288 | });
|
289 | });
|
290 | process.env.NODE_ENV !== "production" ? ButtonBase.propTypes = {
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | |
296 |
|
297 |
|
298 |
|
299 | action: refType,
|
300 | |
301 |
|
302 |
|
303 |
|
304 |
|
305 | centerRipple: PropTypes.bool,
|
306 | |
307 |
|
308 |
|
309 | children: PropTypes.node,
|
310 | |
311 |
|
312 |
|
313 | classes: PropTypes.object,
|
314 | |
315 |
|
316 |
|
317 | className: PropTypes.string,
|
318 | |
319 |
|
320 |
|
321 |
|
322 | component: elementTypeAcceptingRef,
|
323 | |
324 |
|
325 |
|
326 |
|
327 | disabled: PropTypes.bool,
|
328 | |
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 |
|
335 | disableRipple: PropTypes.bool,
|
336 | |
337 |
|
338 |
|
339 |
|
340 | disableTouchRipple: PropTypes.bool,
|
341 | |
342 |
|
343 |
|
344 |
|
345 | focusRipple: PropTypes.bool,
|
346 | |
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 | focusVisibleClassName: PropTypes.string,
|
355 | |
356 |
|
357 |
|
358 | href: PropTypes .any,
|
359 | |
360 |
|
361 |
|
362 |
|
363 | LinkComponent: PropTypes.elementType,
|
364 | |
365 |
|
366 |
|
367 | onBlur: PropTypes.func,
|
368 | |
369 |
|
370 |
|
371 | onClick: PropTypes.func,
|
372 | |
373 |
|
374 |
|
375 | onContextMenu: PropTypes.func,
|
376 | |
377 |
|
378 |
|
379 | onDragLeave: PropTypes.func,
|
380 | |
381 |
|
382 |
|
383 | onFocus: PropTypes.func,
|
384 | |
385 |
|
386 |
|
387 |
|
388 | onFocusVisible: PropTypes.func,
|
389 | |
390 |
|
391 |
|
392 | onKeyDown: PropTypes.func,
|
393 | |
394 |
|
395 |
|
396 | onKeyUp: PropTypes.func,
|
397 | |
398 |
|
399 |
|
400 | onMouseDown: PropTypes.func,
|
401 | |
402 |
|
403 |
|
404 | onMouseLeave: PropTypes.func,
|
405 | |
406 |
|
407 |
|
408 | onMouseUp: PropTypes.func,
|
409 | |
410 |
|
411 |
|
412 | onTouchEnd: PropTypes.func,
|
413 | |
414 |
|
415 |
|
416 | onTouchMove: PropTypes.func,
|
417 | |
418 |
|
419 |
|
420 | onTouchStart: PropTypes.func,
|
421 | |
422 |
|
423 |
|
424 | sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
|
425 | |
426 |
|
427 |
|
428 | tabIndex: PropTypes.number,
|
429 | |
430 |
|
431 |
|
432 | TouchRippleProps: PropTypes.object,
|
433 | |
434 |
|
435 |
|
436 | touchRippleRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
|
437 | current: PropTypes.shape({
|
438 | pulsate: PropTypes.func.isRequired,
|
439 | start: PropTypes.func.isRequired,
|
440 | stop: PropTypes.func.isRequired
|
441 | })
|
442 | })]),
|
443 | |
444 |
|
445 |
|
446 | type: PropTypes.oneOfType([PropTypes.oneOf(['button', 'reset', 'submit']), PropTypes.string])
|
447 | } : void 0;
|
448 | export default ButtonBase; |
\ | No newline at end of file |