Skip to content

Commit c3605b1

Browse files
committed
fix: disabled link
1 parent 00c8d2b commit c3605b1

File tree

6 files changed

+121
-60
lines changed

6 files changed

+121
-60
lines changed

example/storybook-nativewind/src/core-components/nativewind/link/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ cssInterop(UILink, { className: 'style' });
2323
cssInterop(UILink.Text, { className: 'style' });
2424

2525
const linkStyle = tva({
26-
base: 'web:outline-0 web:data-[disabled=true]:cursor-not-allowed web:data-[focus-visible=true]:outline-2 web:data-[focus-visible=true]:outline-primary-700 web:data-[focus-visible=true]:outline data-[disabled=true]:opacity-40 group/link',
26+
base: 'group/link web:outline-0 data-[disabled=true]:web:cursor-not-allowed data-[focus-visible=true]:web:ring-2 data-[focus-visible=true]:web:ring-indicator-primary data-[focus-visible=true]:web:outline-0 data-[disabled=true]:opacity-4 ',
2727
});
2828

2929
const linkTextStyle = tva({
30-
base: 'underline text-info-700 group-hover/link:text-info-600 group-hover/link:no-underline group-active/link:text-info-700 font-normal font-body web:font-sans web:tracking-sm web:my-0 web:bg-transparent web:border-0 web:box-border web:display-inline web:list-none web:margin-0 web:padding-0 web:position-relative web:text-start web:whitespace-pre-wrap web:word-wrap-break-word',
30+
base: 'underline text-info-700 data-[hover=true]:text-info-600 data-[hover=true]:no-underline data-[active=true]:text-info-700 font-normal font-body web:font-sans web:tracking-sm web:my-0 web:bg-transparent web:border-0 web:box-border web:display-inline web:list-none web:margin-0 web:padding-0 web:position-relative web:text-start web:whitespace-pre-wrap web:word-wrap-break-word',
3131

3232
variants: {
3333
isTruncated: {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { createContext, useContext } from 'react';
2+
3+
export const LinkContext = createContext<{
4+
isHovered: boolean;
5+
isFocused: boolean;
6+
isPressed: boolean;
7+
isDisabled: boolean;
8+
isFocusVisible: boolean;
9+
}>({
10+
isHovered: false,
11+
isFocused: false,
12+
isPressed: false,
13+
isDisabled: false,
14+
isFocusVisible: false,
15+
});
16+
export const useLinkContext = () => useContext(LinkContext);
Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import React, { forwardRef } from 'react';
1+
import React, { forwardRef, useMemo } from 'react';
22
import { useLink } from './useLink';
33
import { mergeRefs } from '@gluestack-ui/utils';
44

55
import { composeEventHandlers } from '@gluestack-ui/utils';
66

77
import { useFocusRing, useFocus } from '@react-native-aria/focus';
88
import { useHover, usePress } from '@react-native-aria/interactions';
9+
import { LinkContext } from './Context';
910

1011
export const Link = <LinkProps,>(StyledLink: React.ComponentType<LinkProps>) =>
1112
forwardRef(
@@ -37,60 +38,82 @@ export const Link = <LinkProps,>(StyledLink: React.ComponentType<LinkProps>) =>
3738
href,
3839
onPress,
3940
_ref,
41+
isDisabled,
4042
});
4143

44+
const contextValue = useMemo(() => {
45+
return {
46+
isHovered: isHoveredProp || isHovered,
47+
isFocused: isFocusedProp || isFocused,
48+
isPressed: isPressedProp || isPressed,
49+
isDisabled: isDisabled,
50+
isFocusVisible: isFocusVisibleProp || isFocusVisible,
51+
};
52+
}, [
53+
isHoveredProp,
54+
isHovered,
55+
isFocusedProp,
56+
isFocused,
57+
isPressedProp,
58+
isPressed,
59+
isDisabled,
60+
isFocusVisibleProp,
61+
isFocusVisible,
62+
]);
4263
return (
43-
<StyledLink
44-
ref={mergeRefs([_ref, ref])}
45-
states={{
46-
hover: isHoveredProp || isHovered,
47-
focus: isFocusedProp || isFocused,
48-
active: isPressedProp || isPressed,
49-
disabled: isDisabled,
50-
focusVisible: isFocusVisibleProp || isFocusVisible,
51-
}}
52-
dataSet={{
53-
hover: isHoveredProp || isHovered ? 'true' : 'false',
54-
focus: isFocusedProp || isFocused ? 'true' : 'false',
55-
active: isPressedProp || isPressed ? 'true' : 'false',
56-
disabled: isDisabled ? 'true' : 'false',
57-
focusVisible:
58-
isFocusVisibleProp || isFocusVisible ? 'true' : 'false',
59-
}}
60-
disabled={isDisabled}
61-
{...linkProps}
62-
{...props}
63-
onPressIn={composeEventHandlers(
64-
props?.onPressIn,
65-
pressProps.onPressIn
66-
)}
67-
onPressOut={composeEventHandlers(
68-
props?.onPressOut,
69-
pressProps.onPressOut
70-
)}
71-
// @ts-ignore - web only
72-
onHoverIn={composeEventHandlers(
73-
props?.onHoverIn,
74-
hoverProps.onHoverIn
75-
)}
76-
// @ts-ignore - web only
77-
onHoverOut={composeEventHandlers(
78-
props?.onHoverOut,
79-
hoverProps.onHoverOut
80-
)}
81-
// @ts-ignore - web only
82-
onFocus={composeEventHandlers(
83-
composeEventHandlers(props?.onFocus, focusProps.onFocus),
84-
focusRingProps.onFocus
85-
)}
86-
// @ts-ignore - web only
87-
onBlur={composeEventHandlers(
88-
composeEventHandlers(props?.onBlur, focusProps.onBlur),
89-
focusRingProps.onBlur
90-
)}
91-
>
92-
{children}
93-
</StyledLink>
64+
<LinkContext.Provider value={contextValue}>
65+
<StyledLink
66+
ref={mergeRefs([_ref, ref])}
67+
states={{
68+
hover: isHoveredProp || isHovered,
69+
focus: isFocusedProp || isFocused,
70+
active: isPressedProp || isPressed,
71+
disabled: isDisabled,
72+
focusVisible: isFocusVisibleProp || isFocusVisible,
73+
}}
74+
dataSet={{
75+
hover: isHoveredProp || isHovered ? 'true' : 'false',
76+
focus: isFocusedProp || isFocused ? 'true' : 'false',
77+
active: isPressedProp || isPressed ? 'true' : 'false',
78+
disabled: isDisabled ? 'true' : 'false',
79+
focusVisible:
80+
isFocusVisibleProp || isFocusVisible ? 'true' : 'false',
81+
}}
82+
disabled={isDisabled}
83+
{...linkProps}
84+
{...props}
85+
onPressIn={composeEventHandlers(
86+
props?.onPressIn,
87+
pressProps.onPressIn
88+
)}
89+
onPressOut={composeEventHandlers(
90+
props?.onPressOut,
91+
pressProps.onPressOut
92+
)}
93+
// @ts-ignore - web only
94+
onHoverIn={composeEventHandlers(
95+
props?.onHoverIn,
96+
hoverProps.onHoverIn
97+
)}
98+
// @ts-ignore - web only
99+
onHoverOut={composeEventHandlers(
100+
props?.onHoverOut,
101+
hoverProps.onHoverOut
102+
)}
103+
// @ts-ignore - web only
104+
onFocus={composeEventHandlers(
105+
composeEventHandlers(props?.onFocus, focusProps.onFocus),
106+
focusRingProps.onFocus
107+
)}
108+
// @ts-ignore - web only
109+
onBlur={composeEventHandlers(
110+
composeEventHandlers(props?.onBlur, focusProps.onBlur),
111+
focusRingProps.onBlur
112+
)}
113+
>
114+
{children}
115+
</StyledLink>
116+
</LinkContext.Provider>
94117
);
95118
}
96119
);

packages/unstyled/link/src/LinkText.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
11
import React, { forwardRef } from 'react';
2-
2+
import { useLinkContext } from './Context';
33
export const LinkText = (StyledButtonText: any) =>
44
forwardRef(({ children, ...props }: any, ref?: any) => {
5+
const { isHovered, isFocused, isPressed, isDisabled, isFocusVisible } =
6+
useLinkContext();
57
return (
6-
<StyledButtonText ref={ref} {...props}>
8+
<StyledButtonText
9+
ref={ref}
10+
{...props}
11+
states={{
12+
hover: isHovered,
13+
focus: isFocused,
14+
active: isPressed,
15+
disabled: isDisabled,
16+
focusVisible: isFocusVisible,
17+
}}
18+
dataSet={{
19+
hover: isHovered,
20+
focus: isFocused,
21+
active: isPressed,
22+
disabled: isDisabled,
23+
focusVisible: isFocusVisible,
24+
}}
25+
>
726
{children}
827
</StyledButtonText>
928
);

packages/unstyled/link/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export type IUseLinkProp = {
2626
isExternal?: boolean;
2727
onPress: ((event?: GestureResponderEvent) => any) | null | undefined;
2828
_ref: MutableRefObject<any>;
29+
isDisabled?: boolean;
2930
};
3031

3132
export type ILinkComponentType<Root, TextProps> =

packages/unstyled/link/src/useLink.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ const addOnPressFunctionality = (href: string | any, callback: any) => {
1212
};
1313

1414
export function useLink(props: IUseLinkProp) {
15-
const { href, isExternal, onPress, _ref } = props;
15+
const { href, isExternal, onPress, _ref, isDisabled } = props;
1616

1717
let platformLinkProps = {};
1818

1919
if (Platform.OS === 'web') {
2020
platformLinkProps = {
21-
href,
22-
onPress: onPress,
21+
'href': isDisabled ? undefined : href,
22+
'onPress': isDisabled ? undefined : onPress,
23+
'aria-disabled': isDisabled,
24+
'tabIndex': isDisabled ? -1 : 0,
2325
};
2426
// Adding target to a tag created by RN-Web
2527
if (isExternal && _ref.current) {
@@ -29,7 +31,7 @@ export function useLink(props: IUseLinkProp) {
2931
} else {
3032
platformLinkProps = {
3133
onPress: () => {
32-
addOnPressFunctionality(href, onPress);
34+
if (!isDisabled) addOnPressFunctionality(href, onPress);
3335
},
3436
href,
3537
};

0 commit comments

Comments
 (0)