UNPKG

14.6 kBJavaScriptView Raw
1"use strict";
2'use client';
3
4var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
6Object.defineProperty(exports, "__esModule", {
7 value: true
8});
9exports.default = exports.ButtonBaseRoot = void 0;
10var React = _interopRequireWildcard(require("react"));
11var _propTypes = _interopRequireDefault(require("prop-types"));
12var _clsx = _interopRequireDefault(require("clsx"));
13var _refType = _interopRequireDefault(require("@mui/utils/refType"));
14var _elementTypeAcceptingRef = _interopRequireDefault(require("@mui/utils/elementTypeAcceptingRef"));
15var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
16var _isFocusVisible = _interopRequireDefault(require("@mui/utils/isFocusVisible"));
17var _zeroStyled = require("../zero-styled");
18var _DefaultPropsProvider = require("../DefaultPropsProvider");
19var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
20var _useEventCallback = _interopRequireDefault(require("../utils/useEventCallback"));
21var _useLazyRipple = _interopRequireDefault(require("../useLazyRipple"));
22var _TouchRipple = _interopRequireDefault(require("./TouchRipple"));
23var _buttonBaseClasses = _interopRequireWildcard(require("./buttonBaseClasses"));
24var _jsxRuntime = require("react/jsx-runtime");
25const useUtilityClasses = ownerState => {
26 const {
27 disabled,
28 focusVisible,
29 focusVisibleClassName,
30 classes
31 } = ownerState;
32 const slots = {
33 root: ['root', disabled && 'disabled', focusVisible && 'focusVisible']
34 };
35 const composedClasses = (0, _composeClasses.default)(slots, _buttonBaseClasses.getButtonBaseUtilityClass, classes);
36 if (focusVisible && focusVisibleClassName) {
37 composedClasses.root += ` ${focusVisibleClassName}`;
38 }
39 return composedClasses;
40};
41const ButtonBaseRoot = exports.ButtonBaseRoot = (0, _zeroStyled.styled)('button', {
42 name: 'MuiButtonBase',
43 slot: 'Root',
44 overridesResolver: (props, styles) => styles.root
45})({
46 display: 'inline-flex',
47 alignItems: 'center',
48 justifyContent: 'center',
49 position: 'relative',
50 boxSizing: 'border-box',
51 WebkitTapHighlightColor: 'transparent',
52 backgroundColor: 'transparent',
53 // Reset default value
54 // We disable the focus ring for mouse, touch and keyboard users.
55 outline: 0,
56 border: 0,
57 margin: 0,
58 // Remove the margin in Safari
59 borderRadius: 0,
60 padding: 0,
61 // Remove the padding in Firefox
62 cursor: 'pointer',
63 userSelect: 'none',
64 verticalAlign: 'middle',
65 MozAppearance: 'none',
66 // Reset
67 WebkitAppearance: 'none',
68 // Reset
69 textDecoration: 'none',
70 // So we take precedent over the style of a native <a /> element.
71 color: 'inherit',
72 '&::-moz-focus-inner': {
73 borderStyle: 'none' // Remove Firefox dotted outline.
74 },
75 [`&.${_buttonBaseClasses.default.disabled}`]: {
76 pointerEvents: 'none',
77 // Disable link interactions
78 cursor: 'default'
79 },
80 '@media print': {
81 colorAdjust: 'exact'
82 }
83});
84
85/**
86 * `ButtonBase` contains as few styles as possible.
87 * It aims to be a simple building block for creating a button.
88 * It contains a load of style reset and some focus/ripple logic.
89 */
90const ButtonBase = /*#__PURE__*/React.forwardRef(function ButtonBase(inProps, ref) {
91 const props = (0, _DefaultPropsProvider.useDefaultProps)({
92 props: inProps,
93 name: 'MuiButtonBase'
94 });
95 const {
96 action,
97 centerRipple = false,
98 children,
99 className,
100 component = 'button',
101 disabled = false,
102 disableRipple = false,
103 disableTouchRipple = false,
104 focusRipple = false,
105 focusVisibleClassName,
106 LinkComponent = 'a',
107 onBlur,
108 onClick,
109 onContextMenu,
110 onDragLeave,
111 onFocus,
112 onFocusVisible,
113 onKeyDown,
114 onKeyUp,
115 onMouseDown,
116 onMouseLeave,
117 onMouseUp,
118 onTouchEnd,
119 onTouchMove,
120 onTouchStart,
121 tabIndex = 0,
122 TouchRippleProps,
123 touchRippleRef,
124 type,
125 ...other
126 } = props;
127 const buttonRef = React.useRef(null);
128 const ripple = (0, _useLazyRipple.default)();
129 const handleRippleRef = (0, _useForkRef.default)(ripple.ref, touchRippleRef);
130 const [focusVisible, setFocusVisible] = React.useState(false);
131 if (disabled && focusVisible) {
132 setFocusVisible(false);
133 }
134 React.useImperativeHandle(action, () => ({
135 focusVisible: () => {
136 setFocusVisible(true);
137 buttonRef.current.focus();
138 }
139 }), []);
140 const enableTouchRipple = ripple.shouldMount && !disableRipple && !disabled;
141 React.useEffect(() => {
142 if (focusVisible && focusRipple && !disableRipple) {
143 ripple.pulsate();
144 }
145 }, [disableRipple, focusRipple, focusVisible, ripple]);
146 function useRippleHandler(rippleAction, eventCallback, skipRippleAction = disableTouchRipple) {
147 return (0, _useEventCallback.default)(event => {
148 if (eventCallback) {
149 eventCallback(event);
150 }
151 const ignore = skipRippleAction;
152 if (!ignore) {
153 ripple[rippleAction](event);
154 }
155 return true;
156 });
157 }
158 const handleMouseDown = useRippleHandler('start', onMouseDown);
159 const handleContextMenu = useRippleHandler('stop', onContextMenu);
160 const handleDragLeave = useRippleHandler('stop', onDragLeave);
161 const handleMouseUp = useRippleHandler('stop', onMouseUp);
162 const handleMouseLeave = useRippleHandler('stop', event => {
163 if (focusVisible) {
164 event.preventDefault();
165 }
166 if (onMouseLeave) {
167 onMouseLeave(event);
168 }
169 });
170 const handleTouchStart = useRippleHandler('start', onTouchStart);
171 const handleTouchEnd = useRippleHandler('stop', onTouchEnd);
172 const handleTouchMove = useRippleHandler('stop', onTouchMove);
173 const handleBlur = useRippleHandler('stop', event => {
174 if (!(0, _isFocusVisible.default)(event.target)) {
175 setFocusVisible(false);
176 }
177 if (onBlur) {
178 onBlur(event);
179 }
180 }, false);
181 const handleFocus = (0, _useEventCallback.default)(event => {
182 // Fix for https://github.com/facebook/react/issues/7769
183 if (!buttonRef.current) {
184 buttonRef.current = event.currentTarget;
185 }
186 if ((0, _isFocusVisible.default)(event.target)) {
187 setFocusVisible(true);
188 if (onFocusVisible) {
189 onFocusVisible(event);
190 }
191 }
192 if (onFocus) {
193 onFocus(event);
194 }
195 });
196 const isNonNativeButton = () => {
197 const button = buttonRef.current;
198 return component && component !== 'button' && !(button.tagName === 'A' && button.href);
199 };
200 const handleKeyDown = (0, _useEventCallback.default)(event => {
201 // Check if key is already down to avoid repeats being counted as multiple activations
202 if (focusRipple && !event.repeat && focusVisible && event.key === ' ') {
203 ripple.stop(event, () => {
204 ripple.start(event);
205 });
206 }
207 if (event.target === event.currentTarget && isNonNativeButton() && event.key === ' ') {
208 event.preventDefault();
209 }
210 if (onKeyDown) {
211 onKeyDown(event);
212 }
213
214 // Keyboard accessibility for non interactive elements
215 if (event.target === event.currentTarget && isNonNativeButton() && event.key === 'Enter' && !disabled) {
216 event.preventDefault();
217 if (onClick) {
218 onClick(event);
219 }
220 }
221 });
222 const handleKeyUp = (0, _useEventCallback.default)(event => {
223 // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
224 // https://codesandbox.io/p/sandbox/button-keyup-preventdefault-dn7f0
225 if (focusRipple && event.key === ' ' && focusVisible && !event.defaultPrevented) {
226 ripple.stop(event, () => {
227 ripple.pulsate(event);
228 });
229 }
230 if (onKeyUp) {
231 onKeyUp(event);
232 }
233
234 // Keyboard accessibility for non interactive elements
235 if (onClick && event.target === event.currentTarget && isNonNativeButton() && event.key === ' ' && !event.defaultPrevented) {
236 onClick(event);
237 }
238 });
239 let ComponentProp = component;
240 if (ComponentProp === 'button' && (other.href || other.to)) {
241 ComponentProp = LinkComponent;
242 }
243 const buttonProps = {};
244 if (ComponentProp === 'button') {
245 buttonProps.type = type === undefined ? 'button' : type;
246 buttonProps.disabled = disabled;
247 } else {
248 if (!other.href && !other.to) {
249 buttonProps.role = 'button';
250 }
251 if (disabled) {
252 buttonProps['aria-disabled'] = disabled;
253 }
254 }
255 const handleRef = (0, _useForkRef.default)(ref, buttonRef);
256 const ownerState = {
257 ...props,
258 centerRipple,
259 component,
260 disabled,
261 disableRipple,
262 disableTouchRipple,
263 focusRipple,
264 tabIndex,
265 focusVisible
266 };
267 const classes = useUtilityClasses(ownerState);
268 return /*#__PURE__*/(0, _jsxRuntime.jsxs)(ButtonBaseRoot, {
269 as: ComponentProp,
270 className: (0, _clsx.default)(classes.root, className),
271 ownerState: ownerState,
272 onBlur: handleBlur,
273 onClick: onClick,
274 onContextMenu: handleContextMenu,
275 onFocus: handleFocus,
276 onKeyDown: handleKeyDown,
277 onKeyUp: handleKeyUp,
278 onMouseDown: handleMouseDown,
279 onMouseLeave: handleMouseLeave,
280 onMouseUp: handleMouseUp,
281 onDragLeave: handleDragLeave,
282 onTouchEnd: handleTouchEnd,
283 onTouchMove: handleTouchMove,
284 onTouchStart: handleTouchStart,
285 ref: handleRef,
286 tabIndex: disabled ? -1 : tabIndex,
287 type: type,
288 ...buttonProps,
289 ...other,
290 children: [children, enableTouchRipple ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_TouchRipple.default, {
291 ref: handleRippleRef,
292 center: centerRipple,
293 ...TouchRippleProps
294 }) : null]
295 });
296});
297process.env.NODE_ENV !== "production" ? ButtonBase.propTypes /* remove-proptypes */ = {
298 // ┌────────────────────────────── Warning ──────────────────────────────┐
299 // │ These PropTypes are generated from the TypeScript type definitions. │
300 // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
301 // └─────────────────────────────────────────────────────────────────────┘
302 /**
303 * A ref for imperative actions.
304 * It currently only supports `focusVisible()` action.
305 */
306 action: _refType.default,
307 /**
308 * If `true`, the ripples are centered.
309 * They won't start at the cursor interaction position.
310 * @default false
311 */
312 centerRipple: _propTypes.default.bool,
313 /**
314 * The content of the component.
315 */
316 children: _propTypes.default.node,
317 /**
318 * Override or extend the styles applied to the component.
319 */
320 classes: _propTypes.default.object,
321 /**
322 * @ignore
323 */
324 className: _propTypes.default.string,
325 /**
326 * The component used for the root node.
327 * Either a string to use a HTML element or a component.
328 */
329 component: _elementTypeAcceptingRef.default,
330 /**
331 * If `true`, the component is disabled.
332 * @default false
333 */
334 disabled: _propTypes.default.bool,
335 /**
336 * If `true`, the ripple effect is disabled.
337 *
338 * ⚠️ Without a ripple there is no styling for :focus-visible by default. Be sure
339 * to highlight the element by applying separate styles with the `.Mui-focusVisible` class.
340 * @default false
341 */
342 disableRipple: _propTypes.default.bool,
343 /**
344 * If `true`, the touch ripple effect is disabled.
345 * @default false
346 */
347 disableTouchRipple: _propTypes.default.bool,
348 /**
349 * If `true`, the base button will have a keyboard focus ripple.
350 * @default false
351 */
352 focusRipple: _propTypes.default.bool,
353 /**
354 * This prop can help identify which element has keyboard focus.
355 * The class name will be applied when the element gains the focus through keyboard interaction.
356 * It's a polyfill for the [CSS :focus-visible selector](https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo).
357 * The rationale for using this feature [is explained here](https://github.com/WICG/focus-visible/blob/HEAD/explainer.md).
358 * A [polyfill can be used](https://github.com/WICG/focus-visible) to apply a `focus-visible` class to other components
359 * if needed.
360 */
361 focusVisibleClassName: _propTypes.default.string,
362 /**
363 * @ignore
364 */
365 href: _propTypes.default /* @typescript-to-proptypes-ignore */.any,
366 /**
367 * The component used to render a link when the `href` prop is provided.
368 * @default 'a'
369 */
370 LinkComponent: _propTypes.default.elementType,
371 /**
372 * @ignore
373 */
374 onBlur: _propTypes.default.func,
375 /**
376 * @ignore
377 */
378 onClick: _propTypes.default.func,
379 /**
380 * @ignore
381 */
382 onContextMenu: _propTypes.default.func,
383 /**
384 * @ignore
385 */
386 onDragLeave: _propTypes.default.func,
387 /**
388 * @ignore
389 */
390 onFocus: _propTypes.default.func,
391 /**
392 * Callback fired when the component is focused with a keyboard.
393 * We trigger a `onFocus` callback too.
394 */
395 onFocusVisible: _propTypes.default.func,
396 /**
397 * @ignore
398 */
399 onKeyDown: _propTypes.default.func,
400 /**
401 * @ignore
402 */
403 onKeyUp: _propTypes.default.func,
404 /**
405 * @ignore
406 */
407 onMouseDown: _propTypes.default.func,
408 /**
409 * @ignore
410 */
411 onMouseLeave: _propTypes.default.func,
412 /**
413 * @ignore
414 */
415 onMouseUp: _propTypes.default.func,
416 /**
417 * @ignore
418 */
419 onTouchEnd: _propTypes.default.func,
420 /**
421 * @ignore
422 */
423 onTouchMove: _propTypes.default.func,
424 /**
425 * @ignore
426 */
427 onTouchStart: _propTypes.default.func,
428 /**
429 * The system prop that allows defining system overrides as well as additional CSS styles.
430 */
431 sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object]),
432 /**
433 * @default 0
434 */
435 tabIndex: _propTypes.default.number,
436 /**
437 * Props applied to the `TouchRipple` element.
438 */
439 TouchRippleProps: _propTypes.default.object,
440 /**
441 * A ref that points to the `TouchRipple` element.
442 */
443 touchRippleRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.shape({
444 current: _propTypes.default.shape({
445 pulsate: _propTypes.default.func.isRequired,
446 start: _propTypes.default.func.isRequired,
447 stop: _propTypes.default.func.isRequired
448 })
449 })]),
450 /**
451 * @ignore
452 */
453 type: _propTypes.default.oneOfType([_propTypes.default.oneOf(['button', 'reset', 'submit']), _propTypes.default.string])
454} : void 0;
455var _default = exports.default = ButtonBase;
\No newline at end of file