@lumx/react 3.19.1-alpha.4 → 3.19.1-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,11 @@
1
1
  import React, { ElementType, ReactNode } from 'react';
2
2
  import { Icon, Placement, Size, Tooltip, Text } from '@lumx/react';
3
3
  import { getRootClassName, handleBasicClasses } from '@lumx/core/js/utils/className';
4
- import { ComponentRef, HasClassName, HasPolymorphicAs, HasRequiredLinkHref, HasTheme } from '@lumx/react/utils/type';
4
+ import { ComponentRef, HasClassName, HasPolymorphicAs, HasTheme } from '@lumx/react/utils/type';
5
5
  import classNames from 'classnames';
6
6
  import { forwardRefPolymorphic } from '@lumx/react/utils/react/forwardRefPolymorphic';
7
7
  import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
8
8
  import { useOverflowTooltipLabel } from '@lumx/react/hooks/useOverflowTooltipLabel';
9
- import { RawClickable } from '@lumx/react/utils/react/RawClickable';
10
9
 
11
10
  type BaseNavigationItemProps = {
12
11
  /** Icon (SVG path). */
@@ -17,6 +16,9 @@ type BaseNavigationItemProps = {
17
16
  isCurrentPage?: boolean;
18
17
  };
19
18
 
19
+ /** Make `href` required when `as` is `a` */
20
+ type RequiredLinkHref<E> = E extends 'a' ? { href: string } : Record<string, unknown>;
21
+
20
22
  /**
21
23
  * Navigation item props
22
24
  */
@@ -24,7 +26,7 @@ export type NavigationItemProps<E extends ElementType = 'a'> = HasPolymorphicAs<
24
26
  HasTheme &
25
27
  HasClassName &
26
28
  BaseNavigationItemProps &
27
- HasRequiredLinkHref<E>;
29
+ RequiredLinkHref<E>;
28
30
 
29
31
  /**
30
32
  * Component display name.
@@ -42,6 +44,8 @@ export const NavigationItem = Object.assign(
42
44
  const theme = useTheme();
43
45
  const { tooltipLabel, labelRef } = useOverflowTooltipLabel(label);
44
46
 
47
+ const buttonProps = Element === 'button' ? { type: 'button' } : {};
48
+
45
49
  return (
46
50
  <li
47
51
  className={classNames(
@@ -53,14 +57,14 @@ export const NavigationItem = Object.assign(
53
57
  )}
54
58
  >
55
59
  <Tooltip label={tooltipLabel} placement={Placement.TOP}>
56
- <RawClickable
57
- as={Element}
60
+ <Element
58
61
  className={handleBasicClasses({
59
62
  prefix: `${CLASSNAME}__link`,
60
63
  isSelected: isCurrentPage,
61
64
  })}
62
65
  ref={ref as React.Ref<any>}
63
66
  aria-current={isCurrentPage ? 'page' : undefined}
67
+ {...buttonProps}
64
68
  {...forwardedProps}
65
69
  >
66
70
  {icon ? (
@@ -70,7 +74,7 @@ export const NavigationItem = Object.assign(
70
74
  <Text as="span" truncate className={`${CLASSNAME}__label`} ref={labelRef}>
71
75
  {label}
72
76
  </Text>
73
- </RawClickable>
77
+ </Element>
74
78
  </Tooltip>
75
79
  </li>
76
80
  );
@@ -9,7 +9,6 @@ import { ThemeProvider, useTheme } from '@lumx/react/utils/theme/ThemeContext';
9
9
  import { useId } from '@lumx/react/hooks/useId';
10
10
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
11
11
 
12
- import { RawClickable } from '@lumx/react/utils/react/RawClickable';
13
12
  import { CLASSNAME as ITEM_CLASSNAME } from './NavigationItem';
14
13
  import { NavigationContext } from './context';
15
14
 
@@ -53,8 +52,7 @@ export const NavigationSection = forwardRef<NavigationSectionProps, HTMLLIElemen
53
52
  )}
54
53
  ref={ref}
55
54
  >
56
- <RawClickable<'button'>
57
- as="button"
55
+ <button
58
56
  {...forwardedProps}
59
57
  aria-controls={sectionId}
60
58
  aria-expanded={isOpen}
@@ -64,6 +62,7 @@ export const NavigationSection = forwardRef<NavigationSectionProps, HTMLLIElemen
64
62
  setIsOpen(!isOpen);
65
63
  event.stopPropagation();
66
64
  }}
65
+ type="button"
67
66
  >
68
67
  {icon ? <Icon className={`${ITEM_CLASSNAME}__icon`} icon={icon} size={Size.xs} /> : null}
69
68
 
@@ -74,7 +73,7 @@ export const NavigationSection = forwardRef<NavigationSectionProps, HTMLLIElemen
74
73
  className={classNames(`${ITEM_CLASSNAME}__icon`, `${CLASSNAME}__chevron`)}
75
74
  icon={isOpen ? mdiChevronUp : mdiChevronDown}
76
75
  />
77
- </RawClickable>
76
+ </button>
78
77
  {isOpen &&
79
78
  (isDropdown ? (
80
79
  <Popover
@@ -7,9 +7,10 @@ import { mdiChevronDown, mdiChevronUp } from '@lumx/icons';
7
7
  import { Emphasis, Icon, Size, IconButton, IconButtonProps } from '@lumx/react';
8
8
  import { GenericProps, HasCloseMode, isComponent } from '@lumx/react/utils/type';
9
9
  import { getRootClassName, handleBasicClasses } from '@lumx/core/js/utils/className';
10
+ import { renderLink } from '@lumx/react/utils/react/renderLink';
11
+ import { renderButtonOrLink } from '@lumx/react/utils/react/renderButtonOrLink';
10
12
  import { useId } from '@lumx/react/hooks/useId';
11
13
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
12
- import { RawClickable } from '@lumx/react/utils/react/RawClickable';
13
14
 
14
15
  /**
15
16
  * Defines the props of the component.
@@ -112,15 +113,17 @@ export const SideNavigationItem = forwardRef<SideNavigationItemProps, HTMLLIElem
112
113
  >
113
114
  {shouldSplitActions ? (
114
115
  <div className={`${CLASSNAME}__wrapper`}>
115
- <RawClickable
116
- as={linkAs || (linkProps?.href ? 'a' : 'button')}
117
- {...(linkProps as any)}
118
- className={`${CLASSNAME}__link`}
119
- onClick={onClick}
120
- >
121
- {icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />}
122
- <span>{label}</span>
123
- </RawClickable>
116
+ {renderLink(
117
+ {
118
+ linkAs,
119
+ ...linkProps,
120
+ className: `${CLASSNAME}__link`,
121
+ onClick,
122
+ tabIndex: 0,
123
+ },
124
+ icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />,
125
+ <span>{label}</span>,
126
+ )}
124
127
 
125
128
  <IconButton
126
129
  {...toggleButtonProps}
@@ -133,23 +136,25 @@ export const SideNavigationItem = forwardRef<SideNavigationItemProps, HTMLLIElem
133
136
  />
134
137
  </div>
135
138
  ) : (
136
- <RawClickable
137
- as={linkAs || (linkProps?.href ? 'a' : 'button')}
138
- {...linkProps}
139
- className={`${CLASSNAME}__link`}
140
- onClick={onClick}
141
- {...ariaProps}
142
- >
143
- {icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />}
144
- <span>{label}</span>
145
- {hasContent && (
139
+ renderButtonOrLink(
140
+ {
141
+ linkAs,
142
+ ...linkProps,
143
+ className: `${CLASSNAME}__link`,
144
+ tabIndex: 0,
145
+ onClick,
146
+ ...ariaProps,
147
+ },
148
+ icon && <Icon className={`${CLASSNAME}__icon`} icon={icon} size={Size.xs} />,
149
+ <span>{label}</span>,
150
+ hasContent && (
146
151
  <Icon
147
152
  className={`${CLASSNAME}__chevron`}
148
153
  icon={isOpen ? mdiChevronUp : mdiChevronDown}
149
154
  size={Size.xs}
150
155
  />
151
- )}
152
- </RawClickable>
156
+ ),
157
+ )
153
158
  )}
154
159
 
155
160
  {(closeMode === 'hide' || showChildren) && (
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { DisabledStateProvider } from '@lumx/react/utils';
4
4
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
5
5
  import { queryByClassName } from '@lumx/react/testing/utils/queries';
6
- import { fireEvent, render, screen } from '@testing-library/react';
6
+ import { fireEvent, render } from '@testing-library/react';
7
7
  import { Thumbnail, ThumbnailProps } from './Thumbnail';
8
8
 
9
9
  const CLASSNAME = Thumbnail.className as string;
@@ -28,19 +28,8 @@ describe(`<${Thumbnail.displayName}>`, () => {
28
28
  },
29
29
  });
30
30
 
31
- describe('clickable button', () => {
32
- it('should render clickable button', async () => {
33
- const onClick = jest.fn();
34
- const { thumbnail } = setup({ onClick, alt: 'Name' });
35
- const button = screen.getByRole('button', { name: 'Name' });
36
- expect(button).toBe(thumbnail);
37
- expect(button).toHaveAttribute('type', 'button');
38
-
39
- fireEvent.click(thumbnail as HTMLElement);
40
- expect(onClick).toHaveBeenCalled();
41
- });
42
-
43
- it('should not render button in disabled context', () => {
31
+ describe('disabled state', () => {
32
+ it('should not be clickable when disabled from context', () => {
44
33
  const onClick = jest.fn();
45
34
  const { thumbnail, container } = setup(
46
35
  { onClick, 'aria-label': 'thumbnail' },
@@ -58,21 +47,8 @@ describe(`<${Thumbnail.displayName}>`, () => {
58
47
  fireEvent.click(thumbnail as HTMLElement);
59
48
  expect(onClick).not.toHaveBeenCalled();
60
49
  });
61
- });
62
-
63
- describe('clickable link', () => {
64
- it('should render clickable link', async () => {
65
- const onClick = jest.fn((evt) => evt.preventDefault());
66
- const { thumbnail } = setup({ linkProps: { href: '#' }, onClick, alt: 'Name' });
67
- const link = screen.getByRole('link');
68
- expect(link).toBe(thumbnail);
69
- expect(link).toHaveAttribute('href', '#');
70
-
71
- fireEvent.click(thumbnail as HTMLElement);
72
- expect(onClick).toHaveBeenCalled();
73
- });
74
50
 
75
- it('should not render link in disabled context', () => {
51
+ it('should have no href when disabled from context', () => {
76
52
  const { container, thumbnail } = setup(
77
53
  { linkAs: 'a', linkProps: { href: '#' }, 'aria-label': 'thumbnail' },
78
54
  {
@@ -22,7 +22,6 @@ import { useTheme } from '@lumx/react/utils/theme/ThemeContext';
22
22
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
23
23
 
24
24
  import { useDisableStateProps } from '@lumx/react/utils/disabled';
25
- import { RawClickable } from '@lumx/react/utils/react/RawClickable';
26
25
  import { FocusPoint, ThumbnailSize, ThumbnailVariant } from './types';
27
26
 
28
27
  type ImgHTMLProps = ImgHTMLAttributes<HTMLImageElement>;
@@ -101,7 +100,7 @@ const DEFAULT_PROPS: Partial<ThumbnailProps> = {
101
100
  * @return React element.
102
101
  */
103
102
  export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
104
- const { isAnyDisabled, otherProps, disabledStateProps } = useDisableStateProps(props);
103
+ const { isAnyDisabled, otherProps } = useDisableStateProps(props);
105
104
  const defaultTheme = useTheme() || Theme.light;
106
105
  const {
107
106
  align,
@@ -152,17 +151,18 @@ export const Thumbnail = forwardRef<ThumbnailProps>((props, ref) => {
152
151
  }
153
152
 
154
153
  const isLink = Boolean(linkProps?.href || linkAs);
155
- const isClickable = !isAnyDisabled && Boolean(isLink || !!forwardedProps.onClick);
154
+ const isButton = !!forwardedProps.onClick;
155
+ const isClickable = !isAnyDisabled && (isButton || isLink);
156
156
 
157
- const Wrapper: any = isClickable ? RawClickable : 'div';
157
+ let Wrapper: any = 'div';
158
158
  const wrapperProps = { ...forwardedProps };
159
- if (isClickable) {
160
- Object.assign(wrapperProps, { as: linkAs || (linkProps?.href ? 'a' : 'button') }, disabledStateProps);
161
- if (isLink) {
162
- Object.assign(wrapperProps, linkProps);
163
- } else {
164
- wrapperProps['aria-label'] = forwardedProps['aria-label'] || alt;
165
- }
159
+ if (!isAnyDisabled && isLink) {
160
+ Wrapper = linkAs || 'a';
161
+ Object.assign(wrapperProps, linkProps);
162
+ } else if (!isAnyDisabled && isButton) {
163
+ Wrapper = 'button';
164
+ wrapperProps.type = forwardedProps.type || 'button';
165
+ wrapperProps['aria-label'] = forwardedProps['aria-label'] || alt;
166
166
  }
167
167
 
168
168
  // If we have a loading placeholder image that is really loaded (complete)
@@ -0,0 +1,16 @@
1
+ import React, { ReactElement, ReactNode } from 'react';
2
+ import { renderLink } from './renderLink';
3
+
4
+ interface Props {
5
+ linkAs?: any;
6
+ href?: any;
7
+ }
8
+
9
+ /**
10
+ * Render <button> HTML component, fallbacks to `<a>` when a `href` is provided or a custom component with `linkAs`.
11
+ */
12
+ export const renderButtonOrLink = <P extends Props>(props: P, ...children: ReactNode[]): ReactElement => {
13
+ const { linkAs, href, ...forwardedProps } = props;
14
+ if (linkAs || href) return renderLink(props, ...children);
15
+ return React.createElement('button', { type: 'button', ...forwardedProps }, ...children);
16
+ };
@@ -0,0 +1,17 @@
1
+ import React, { ReactElement, ReactNode } from 'react';
2
+
3
+ interface Props {
4
+ linkAs?: any;
5
+ }
6
+
7
+ /**
8
+ * Render link with default <a> HTML component or a custom one provided by `linkAs`.
9
+ *
10
+ * Can be used to inject the `Link` component from `react-router` and provide better a11y on LumX components.
11
+ *
12
+ * @param linkAs Custom link component.
13
+ * @param children Link children.
14
+ * @return A link.
15
+ */
16
+ export const renderLink = <P extends Props>({ linkAs, ...forwardedProps }: P, ...children: ReactNode[]): ReactElement =>
17
+ React.createElement(linkAs || 'a', forwardedProps, ...children);
@@ -6,4 +6,3 @@ export type { HasPolymorphicAs } from './HasPolymorphicAs';
6
6
  export { isComponent } from './isComponent';
7
7
  export { isComponentType } from './isComponentType';
8
8
  export type { MaybeElementOrRef } from './MaybeElementOrRef';
9
- export type { HasRequiredLinkHref } from './HasRequiredLinkHref';
package/utils/index.d.ts CHANGED
@@ -71,7 +71,7 @@ type DisabledStateProviderProps = DisabledStateContextValue & {
71
71
  * Disabled state provider.
72
72
  * All nested LumX Design System components inherit this disabled state.
73
73
  */
74
- declare function DisabledStateProvider({ children, ...value }: DisabledStateProviderProps): React.JSX.Element;
74
+ declare function DisabledStateProvider({ children, ...value }: DisabledStateProviderProps): JSX.Element;
75
75
  /**
76
76
  * Get DisabledState context value
77
77
  */
package/utils/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { C as ClickAwayProvider, D as DisabledStateProvider, P as Portal, c as PortalProvider, u as useDisabledStateContext } from '../_internal/index.js';
1
+ export { C as ClickAwayProvider, D as DisabledStateProvider, P as Portal, b as PortalProvider, u as useDisabledStateContext } from '../_internal/index.js';
2
2
  //# sourceMappingURL=index.js.map
@@ -1,153 +0,0 @@
1
- import React from 'react';
2
- import { render, screen } from '@testing-library/react';
3
- import userEvent from '@testing-library/user-event';
4
- import { RawClickable, RawClickableProps } from './RawClickable';
5
- import { CustomLink } from '../../stories/utils/CustomLink';
6
-
7
- /**
8
- * Mounts the component and returns common DOM elements / data needed in multiple tests.
9
- */
10
- const setup = (props: RawClickableProps<any>) => {
11
- render(<RawClickable {...props} data-testid="raw-element" />);
12
- const element = screen.getByTestId('raw-element');
13
- return { props, element };
14
- };
15
-
16
- describe(`<RawClickable>`, () => {
17
- describe('as a button', () => {
18
- it('should render a button by default', () => {
19
- const { element } = setup({ as: 'button', children: 'Click me' });
20
- expect(element.tagName).toBe('BUTTON');
21
- expect(element).toHaveAttribute('type', 'button');
22
- expect(screen.getByRole('button', { name: 'Click me' })).toBe(element);
23
- });
24
-
25
- it('should trigger onClick', async () => {
26
- const onClick = jest.fn();
27
- const { element } = setup({ as: 'button', children: 'Click me', onClick });
28
- await userEvent.click(element);
29
- expect(onClick).toHaveBeenCalledTimes(1);
30
- });
31
-
32
- it('should be disabled with `disabled` prop', async () => {
33
- const onClick = jest.fn();
34
- const { element } = setup({ as: 'button', children: 'Click me', onClick, disabled: true });
35
- expect(element).toBeDisabled();
36
- await userEvent.click(element);
37
- expect(onClick).not.toHaveBeenCalled();
38
- });
39
-
40
- it('should be disabled with `isDisabled` prop', async () => {
41
- const onClick = jest.fn();
42
- const { element } = setup({ as: 'button', children: 'Click me', onClick, isDisabled: true });
43
- expect(element).toBeDisabled();
44
- await userEvent.click(element);
45
- expect(onClick).not.toHaveBeenCalled();
46
- });
47
-
48
- it('should be aria-disabled with `aria-disabled` prop', async () => {
49
- const onClick = jest.fn();
50
- const { element } = setup({ as: 'button', children: 'Click me', onClick, 'aria-disabled': true });
51
- expect(element).not.toBeDisabled();
52
- expect(element).toHaveAttribute('aria-disabled', 'true');
53
- await userEvent.click(element);
54
- expect(onClick).not.toHaveBeenCalled();
55
- });
56
- });
57
-
58
- describe('as a link', () => {
59
- const href = 'https://example.com';
60
-
61
- it('should render a link with `href` prop', () => {
62
- const { element } = setup({ as: 'a', children: 'Click me', href });
63
- expect(element.tagName).toBe('A');
64
- expect(element).toHaveAttribute('href', href);
65
- expect(screen.getByRole('link', { name: 'Click me' })).toBe(element);
66
- });
67
-
68
- it('should trigger onClick', async () => {
69
- const onClick = jest.fn((evt) => evt.preventDefault());
70
- const { element } = setup({ as: 'a', children: 'Click me', href, onClick });
71
- await userEvent.click(element);
72
- expect(onClick).toHaveBeenCalledTimes(1);
73
- });
74
-
75
- it('should be disabled with `disabled` prop', async () => {
76
- const onClick = jest.fn();
77
- const { element } = setup({ as: 'a', children: 'Click me', href, onClick, disabled: true });
78
- expect(element).toHaveAttribute('aria-disabled', 'true');
79
- expect(element).toHaveAttribute('tabindex', '-1');
80
- await userEvent.click(element);
81
- expect(onClick).not.toHaveBeenCalled();
82
- });
83
-
84
- it('should be disabled with `isDisabled` prop', async () => {
85
- const onClick = jest.fn();
86
- const { element } = setup({ as: 'a', children: 'Click me', href, onClick, isDisabled: true });
87
- expect(element).toHaveAttribute('aria-disabled', 'true');
88
- expect(element).toHaveAttribute('tabindex', '-1');
89
- await userEvent.click(element);
90
- expect(onClick).not.toHaveBeenCalled();
91
- });
92
-
93
- it('should be aria-disabled with `aria-disabled` prop', async () => {
94
- const onClick = jest.fn();
95
- const { element } = setup({ as: 'a', children: 'Click me', href, onClick, 'aria-disabled': true });
96
- expect(element).toHaveAttribute('aria-disabled', 'true');
97
- await userEvent.click(element);
98
- expect(onClick).not.toHaveBeenCalled();
99
- });
100
- });
101
-
102
- describe('as a custom component', () => {
103
- it('should render a custom component with `linkAs` prop', () => {
104
- const { element } = setup({ as: CustomLink, children: 'Click me' });
105
- expect(element).toHaveAttribute('data-custom-link');
106
- });
107
-
108
- it('should trigger onClick', async () => {
109
- const onClick = jest.fn();
110
- const { element } = setup({ as: CustomLink, children: 'Click me', onClick });
111
- expect(element).toHaveAttribute('data-custom-link');
112
- await userEvent.click(element);
113
- expect(onClick).toHaveBeenCalledTimes(1);
114
- });
115
-
116
- it('should be disabled with `disabled` prop', async () => {
117
- const onClick = jest.fn();
118
- const { element } = setup({ as: CustomLink, children: 'Click me', onClick, disabled: true });
119
- expect(element).toHaveAttribute('data-custom-link');
120
- expect(element).toHaveAttribute('aria-disabled', 'true');
121
- expect(element).toHaveAttribute('tabindex', '-1');
122
- await userEvent.click(element);
123
- expect(onClick).not.toHaveBeenCalled();
124
- });
125
- });
126
-
127
- describe('prop forwarding', () => {
128
- it('should forward className', () => {
129
- const { element } = setup({ as: 'button', className: 'foo bar' });
130
- expect(element).toHaveClass('foo bar');
131
- });
132
-
133
- it('should forward ref and override type in button', () => {
134
- const ref = React.createRef<HTMLButtonElement>();
135
- const { element } = setup({ as: 'button', ref, type: 'submit' });
136
- expect(element).toHaveAttribute('type', 'submit');
137
- expect(ref.current).toBeInstanceOf(HTMLButtonElement);
138
- });
139
-
140
- it('should forward ref and override tabindex in link', () => {
141
- const ref = React.createRef<HTMLAnchorElement>();
142
- const { element } = setup({ as: 'a', ref, href: '#', tabIndex: -1 });
143
- expect(ref.current).toBeInstanceOf(HTMLAnchorElement);
144
- expect(element).toHaveAttribute('tabindex', '-1');
145
- });
146
-
147
- it('should forward ref to custom component', () => {
148
- const ref = React.createRef<HTMLAnchorElement>();
149
- setup({ as: CustomLink, ref });
150
- expect(ref.current).toBeInstanceOf(HTMLAnchorElement);
151
- });
152
- });
153
- });
@@ -1,65 +0,0 @@
1
- import React, { AriaAttributes, ElementType } from 'react';
2
- import { forwardRefPolymorphic } from '@lumx/react/utils/react/forwardRefPolymorphic';
3
- import { ComponentRef, HasPolymorphicAs } from '@lumx/react/utils/type';
4
- import { HasRequiredLinkHref } from '@lumx/react/utils/type/HasRequiredLinkHref';
5
-
6
- type ClickableElement = 'a' | 'button' | ElementType;
7
-
8
- type BaseClickableProps<E extends ClickableElement> = {
9
- children?: React.ReactNode;
10
- isDisabled?: boolean;
11
- disabled?: boolean;
12
- 'aria-disabled'?: AriaAttributes['aria-disabled'];
13
- onClick?: React.MouseEventHandler<E>;
14
- };
15
-
16
- export type RawClickableProps<E extends ClickableElement> = HasPolymorphicAs<E> &
17
- HasRequiredLinkHref<E> &
18
- BaseClickableProps<E>;
19
-
20
- /**
21
- * Render clickable element (link, button or custom element)
22
- * (also does some basic disabled state handling)
23
- */
24
- export const RawClickable = forwardRefPolymorphic(
25
- <E extends ClickableElement>(props: RawClickableProps<E>, ref: ComponentRef<E>) => {
26
- const {
27
- children,
28
- onClick,
29
- disabled,
30
- isDisabled = disabled,
31
- 'aria-disabled': ariaDisabled,
32
- as,
33
- ...forwardedProps
34
- } = props;
35
-
36
- const isAnyDisabled = isDisabled || ariaDisabled === 'true' || ariaDisabled === true;
37
-
38
- const Component = as as any;
39
- let clickableProps;
40
- if (Component === 'button') {
41
- clickableProps = { type: forwardedProps.type || 'button', disabled: isDisabled };
42
- } else {
43
- clickableProps = { tabIndex: isDisabled ? '-1' : forwardedProps.tabIndex };
44
- }
45
-
46
- return (
47
- <Component
48
- ref={ref}
49
- aria-disabled={isAnyDisabled || undefined}
50
- {...forwardedProps}
51
- {...clickableProps}
52
- onClick={(event: any) => {
53
- if (isAnyDisabled) {
54
- event.stopPropagation();
55
- event.preventDefault();
56
- return;
57
- }
58
- onClick?.(event);
59
- }}
60
- >
61
- {children}
62
- </Component>
63
- );
64
- },
65
- );
@@ -1 +0,0 @@
1
- export type HasRequiredLinkHref<E> = E extends 'a' ? { href: string } : Record<string, unknown>;