@spark-web/text-link
Version:
--- title: Text Link storybookPath: navigation-textlink--default isExperimentalPackage: true ---
92 lines (85 loc) • 3.4 kB
JavaScript
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
import { css } from '@emotion/css';
import { Box } from '@spark-web/box';
import { useLinkComponent } from '@spark-web/link';
import { forwardRefWithAs } from '@spark-web/utils/ts';
import { useTextContext, useForegroundTone } from '@spark-web/text';
import { useTheme } from '@spark-web/theme';
import { resetElementStyles, buildDataAttributes } from '@spark-web/utils/internal';
import { jsx } from 'react/jsx-runtime';
import { useComposedRefs } from '@spark-web/utils';
import { forwardRef, useRef, useCallback } from 'react';
var TEXT_LINK_ERROR_MESSAGE = 'TextLink components must be inside `Text`.';
function useTextLink(tag) {
var textContext = useTextContext();
// Limit API surface area; expect style inheritance
if (!textContext) {
throw new Error(TEXT_LINK_ERROR_MESSAGE);
}
var theme = useTheme();
var textColor = useForegroundTone(textContext.tone);
var resetStyles = resetElementStyles(tag);
var linkStyles = {
color: textColor,
cursor: 'pointer',
textDecoration: 'underline',
fontWeight: theme.typography.fontWeight.semibold
};
var styles = [resetStyles, linkStyles];
return styles;
}
var _excluded$1 = ["as", "data"];
/**
* Text links are used as navigational elements. They may appear on their own,
* within a sentence or paragraph, or directly following content.
*
* @note If you are **only** providing "onClick" use `TextLinkButton` instead.
*/
var TextLink = forwardRefWithAs(
// NOTE: we need `forwardRefWithAs` for TS, but we don't want consumers changing the underlying element
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function (_ref, ref) {
_ref.as;
var data = _ref.data,
consumerProps = _objectWithoutProperties(_ref, _excluded$1);
var LinkComponent = useLinkComponent(ref);
var styles = useTextLink('a');
return /*#__PURE__*/jsx(Box, _objectSpread({
as: LinkComponent,
asElement: "a",
ref: ref,
className: css(styles),
data: data
}, consumerProps));
});
var _excluded = ["data"];
// NOTE: Rather than a native `button` element, we render a `span` with the ARIA
// role of "button" to avoid issues with text behaviour. Resolves:
// - alignment
// - truncating
// - wrapping
/** The appearance of `TextLink`, with the semantics of a `<button/>`. */
var TextLinkButton = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
var data = _ref.data,
consumerProps = _objectWithoutProperties(_ref, _excluded);
var styles = useTextLink('span');
var internalRef = useRef(null);
var ref = useComposedRefs(internalRef, forwardedRef);
var handleKeyDown = useCallback(function (event) {
if (event.key === 'Enter' || event.key === ' ') {
var _internalRef$current;
event.preventDefault();
(_internalRef$current = internalRef.current) === null || _internalRef$current === void 0 ? void 0 : _internalRef$current.click();
}
}, [internalRef]);
return /*#__PURE__*/jsx("span", _objectSpread(_objectSpread({
role: "button",
ref: ref,
className: css(styles),
tabIndex: 0,
onKeyDown: handleKeyDown
}, data ? buildDataAttributes(data) : undefined), consumerProps));
});
TextLinkButton.displayName = 'TextLinkButton';
export { TextLink, TextLinkButton };