UNPKG

@atlaskit/button

Version:

A button triggers an event or action. They let users know what will happen next.

218 lines (210 loc) 10.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _react = _interopRequireWildcard(require("react")); var _react2 = require("@emotion/react"); var _analyticsNext = require("@atlaskit/analytics-next"); var _noop = _interopRequireDefault(require("@atlaskit/ds-lib/noop")); var _useAutoFocus = _interopRequireDefault(require("@atlaskit/ds-lib/use-auto-focus")); var _focusRing = _interopRequireDefault(require("@atlaskit/focus-ring")); var _interactionContext = _interopRequireDefault(require("@atlaskit/interaction-context")); var _colors = require("@atlaskit/theme/colors"); var _blockEvents = _interopRequireDefault(require("./block-events")); var _css = require("./css"); var _getIfVisuallyHiddenChildren = require("./get-if-visually-hidden-children"); var _excluded = ["analyticsContext", "appearance", "autoFocus", "buttonCss", "children", "className", "href", "component", "iconAfter", "iconBefore", "interactionName", "isDisabled", "isSelected", "onBlur", "onClick", "onFocus", "onMouseDown", "overlay", "shouldFitContainer", "spacing", "tabIndex", "type", "testId"]; /* eslint-disable @atlaskit/design-system/consistent-css-prop-usage */ /** * @jsxRuntime classic * @jsx jsx */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766 // eslint-disable-next-line no-duplicate-imports function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } // Disabled buttons will still publish events for nested elements in webkit. // We are disabling pointer events on child elements so that // the button will always be the target of events // Note: firefox does not have this behaviour for child elements var noPointerEventsOnChildrenCss = { '> *': { pointerEvents: 'none' } }; /** * These CSS variables consumed by the new icons, to allow them to have appropriate * padding inside Button while also maintaining spacing for the existing icons. * * These styles can be removed once the new icons are fully rolled out, feature flag * platform-visual-refresh-icons is cleaned up, * and we bump Button to set padding based on the new icons. */ var iconBeforeSpacingFixStyle = (0, _react2.css)({ '--ds--button--new-icon-padding-end': "var(--ds-space-025, 2px)", '--ds--button--new-icon-padding-start': "var(--ds-space-050, 4px)", marginInlineStart: "var(--ds-space-negative-025, -2px)" }); var iconAfterSpacingFixStyle = (0, _react2.css)({ '--ds--button--new-icon-padding-end': "var(--ds-space-050, 4px)", '--ds--button--new-icon-padding-start': "var(--ds-space-025, 2px)", marginInlineEnd: "var(--ds-space-negative-025, -2px)" }); var getSpacingFix = function getSpacingFix(children, spacingStyles) { if (!children || (0, _getIfVisuallyHiddenChildren.getIfVisuallyHiddenChildren)(children)) { return null; } return spacingStyles; }; var getChildren = function getChildren(children, childrenStyles) { if ((0, _getIfVisuallyHiddenChildren.getIfVisuallyHiddenChildren)(children)) { return children; } return children ? (0, _react2.jsx)("span", { css: childrenStyles }, children) : null; }; var ButtonBase = /*#__PURE__*/_react.default.forwardRef(function ButtonBase(props, ref) { var analyticsContext = props.analyticsContext, _props$appearance = props.appearance, appearance = _props$appearance === void 0 ? 'default' : _props$appearance, _props$autoFocus = props.autoFocus, autoFocus = _props$autoFocus === void 0 ? false : _props$autoFocus, buttonCss = props.buttonCss, children = props.children, className = props.className, href = props.href, _props$component = props.component, Component = _props$component === void 0 ? href ? 'a' : 'button' : _props$component, iconAfter = props.iconAfter, iconBefore = props.iconBefore, interactionName = props.interactionName, _props$isDisabled = props.isDisabled, isDisabled = _props$isDisabled === void 0 ? false : _props$isDisabled, _props$isSelected = props.isSelected, isSelected = _props$isSelected === void 0 ? false : _props$isSelected, onBlur = props.onBlur, _props$onClick = props.onClick, providedOnClick = _props$onClick === void 0 ? _noop.default : _props$onClick, onFocus = props.onFocus, _props$onMouseDown = props.onMouseDown, providedOnMouseDown = _props$onMouseDown === void 0 ? _noop.default : _props$onMouseDown, overlay = props.overlay, shouldFitContainer = props.shouldFitContainer, _props$spacing = props.spacing, spacing = _props$spacing === void 0 ? 'default' : _props$spacing, _props$tabIndex = props.tabIndex, tabIndex = _props$tabIndex === void 0 ? 0 : _props$tabIndex, _props$type = props.type, type = _props$type === void 0 ? !href ? 'button' : undefined : _props$type, testId = props.testId, rest = (0, _objectWithoutProperties2.default)(props, _excluded); var ourRef = (0, _react.useRef)(); var setRef = (0, _react.useCallback)(function (node) { ourRef.current = node; if (ref == null) { return; } if (typeof ref === 'function') { ref(node); return; } // We can write to ref's `current` property, but Typescript does not like it. // @ts-ignore ref.current = node; }, [ourRef, ref]); // Cross browser auto focusing is pretty broken, so we are doing it ourselves (0, _useAutoFocus.default)(ourRef, autoFocus); var interactionContext = (0, _react.useContext)(_interactionContext.default); var handleClick = (0, _react.useCallback)(function (e, analyticsEvent) { interactionContext && interactionContext.tracePress(interactionName, e.timeStamp); providedOnClick(e, analyticsEvent); }, [providedOnClick, interactionContext, interactionName]); var onClick = (0, _analyticsNext.usePlatformLeafEventHandler)({ fn: handleClick, action: 'clicked', componentName: 'button', packageName: "@atlaskit/button", packageVersion: "0.0.0-development", analyticsData: analyticsContext }); // Button currently calls preventDefault, which is not standard button behaviour var onMouseDown = (0, _react.useCallback)(function (event) { event.preventDefault(); providedOnMouseDown(event); }, [providedOnMouseDown]); // Lose focus when becoming disabled (standard button behaviour) (0, _react.useEffect)(function () { var el = ourRef.current; if (isDisabled && el && el === document.activeElement) { el.blur(); } }, [isDisabled]); // we are 'disabling' input with a button when there is an overlay var hasOverlay = Boolean(overlay); // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766 var fadeStyles = (0, _react2.css)((0, _css.getFadingCss)({ hasOverlay: hasOverlay })); var isInteractive = !isDisabled && !hasOverlay; /** * HACK: Spinner needs to have different colours in the "new" tokens design compared to the old design. * For now, while we support both, these styles reach into Spinner when a theme is set, applies the right color. * Ticket to remove: https://product-fabric.atlassian.net/browse/DSP-2067. */ var spinnerHackCss = {}; if (isSelected || isDisabled || appearance === 'warning') { spinnerHackCss = { '[data-theme] & circle': { stroke: "".concat(isSelected || isDisabled ? "var(--ds-icon-subtle, ".concat(_colors.N500, ")") : "var(--ds-icon-warning-inverse, ".concat(_colors.N500, ")"), " !important") } }; } return (0, _react2.jsx)(_focusRing.default, null, (0, _react2.jsx)(Component, (0, _extends2.default)({}, rest, { ref: setRef // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: className, css: [buttonCss, isInteractive ? null : noPointerEventsOnChildrenCss] // using undefined so that the property doesn't exist when false , "data-has-overlay": hasOverlay ? true : undefined, "data-testid": testId, disabled: isDisabled, href: isInteractive ? href : undefined, onBlur: onBlur, onClick: onClick, onFocus: onFocus, onMouseDown: onMouseDown // Adding a tab index so element is always focusable, even when not a <button> or <a> // Disabling focus via keyboard navigation when disabled // as this is standard button behaviour , tabIndex: isDisabled ? -1 : tabIndex, type: type }, (0, _blockEvents.default)({ isInteractive: isInteractive })), iconBefore ? (0, _react2.jsx)("span", { css: [fadeStyles, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 (0, _css.getIconStyle)({ spacing: spacing }), getSpacingFix(children, iconBeforeSpacingFixStyle)] }, iconBefore) : null, getChildren(children, [fadeStyles, (0, _css.getContentStyle)({ spacing: spacing })]), iconAfter ? (0, _react2.jsx)("span", { css: [fadeStyles, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 (0, _css.getIconStyle)({ spacing: spacing }), getSpacingFix(children, iconAfterSpacingFixStyle)] }, iconAfter) : null, overlay ? (0, _react2.jsx)("span", { css: [_css.overlayCss, spinnerHackCss] }, overlay) : null)); }); // eslint-disable-next-line @repo/internal/react/require-jsdoc var _default = exports.default = ButtonBase;