@toptal/picasso-link 3.0.5-alpha-fx-6095-number-input-misses-type-button-353a18c00.1 → 3.0.5-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.14
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.
- package/dist-package/src/Link/Link.d.ts +15 -0
- package/dist-package/src/Link/Link.d.ts.map +1 -1
- package/dist-package/src/Link/Link.js +24 -7
- package/dist-package/src/Link/Link.js.map +1 -1
- package/package.json +7 -7
- package/src/Link/Link.tsx +67 -33
- package/src/Link/__snapshots__/test.tsx.snap +19 -19
- package/src/Link/test.tsx +312 -67
|
@@ -32,6 +32,21 @@ export declare type Props = BaseProps & AnchorHTMLAttributes<HTMLAnchorElement>
|
|
|
32
32
|
noUnderline?: boolean;
|
|
33
33
|
'aria-disabled'?: boolean;
|
|
34
34
|
};
|
|
35
|
+
declare type ViewModel = {
|
|
36
|
+
className: string;
|
|
37
|
+
href?: string;
|
|
38
|
+
target?: string;
|
|
39
|
+
color?: 'inherit';
|
|
40
|
+
rel?: string;
|
|
41
|
+
onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
|
|
42
|
+
weight: 'inherit' | 'semibold';
|
|
43
|
+
style?: React.CSSProperties;
|
|
44
|
+
tabIndex?: number;
|
|
45
|
+
as: Props['as'];
|
|
46
|
+
ariaDisabled?: boolean;
|
|
47
|
+
nativeHTMLAttributes: Omit<Props, keyof BaseProps>;
|
|
48
|
+
};
|
|
49
|
+
export declare const calculateViewModel: (props: Props) => ViewModel;
|
|
35
50
|
export declare const Link: OverridableComponent<Props>;
|
|
36
51
|
export default Link;
|
|
37
52
|
//# sourceMappingURL=Link.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../../src/Link/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACzE,OAAO,KAAqB,MAAM,OAAO,CAAA;AAEzC,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAG7E,QAAA,MAAM,eAAe,4BAA6B,CAAA;AAClD,QAAA,MAAM,iBAAiB,+BAAgC,CAAA;AAEvD,aAAK,WAAW,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,aAAK,SAAS,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AA0CjD,oBAAY,KAAK,GAAG,SAAS,GAC3B,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IACxC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IAC9D;;;OAGG;IACH,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,CAAA;IACnD,qDAAqD;IACrD,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,iCAAiC;IACjC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAKH,eAAO,MAAM,IAAI,EAAE,oBAAoB,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../../src/Link/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACzE,OAAO,KAAqB,MAAM,OAAO,CAAA;AAEzC,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAG7E,QAAA,MAAM,eAAe,4BAA6B,CAAA;AAClD,QAAA,MAAM,iBAAiB,+BAAgC,CAAA;AAEvD,aAAK,WAAW,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AACrD,aAAK,SAAS,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AA0CjD,oBAAY,KAAK,GAAG,SAAS,GAC3B,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IACxC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IAC9D;;;OAGG;IACH,EAAE,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,CAAA;IACnD,qDAAqD;IACrD,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,iCAAiC;IACjC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAKH,aAAK,SAAS,GAAG;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAA;IAC9D,MAAM,EAAE,SAAS,GAAG,UAAU,CAAA;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;IACf,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,oBAAoB,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,SAAS,CAAC,CAAA;CACnD,CAAA;AAGD,eAAO,MAAM,kBAAkB,UAAW,KAAK,KAAG,SAqDjD,CAAA;AAED,eAAO,MAAM,IAAI,EAAE,oBAAoB,CAAC,KAAK,CA0B3C,CAAA;AAWF,eAAe,IAAI,CAAA"}
|
|
@@ -48,22 +48,39 @@ const COLOR_DISABLED_MAP = {
|
|
|
48
48
|
};
|
|
49
49
|
const defaultColor = 'blue';
|
|
50
50
|
const defaultVariant = 'anchor';
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const nativeHTMLAttributes =
|
|
51
|
+
/* eslint-disable complexity */
|
|
52
|
+
export const calculateViewModel = (props) => {
|
|
53
|
+
const { href, onClick, className, as = 'a', color: inputColor = 'blue', style, variant: inputVariant = 'anchor', tabIndex, target, rel, disabled, visited = false, noUnderline, 'aria-disabled': ariaDisabled } = props, nativeHTMLAttributes = __rest(props, ["href", "onClick", "className", "as", "color", "style", "variant", "tabIndex", "target", "rel", "disabled", "visited", "noUnderline", 'aria-disabled']);
|
|
54
54
|
const sanitizedRel = sanitizeRel(rel, target);
|
|
55
55
|
// When Link is used as={Link}, TypeScript can't ensure the input to the Link is compatible with its Props type.
|
|
56
56
|
const color = supportedColors.includes(inputColor) ? inputColor : defaultColor;
|
|
57
57
|
const variant = supportedVariants.includes(inputVariant)
|
|
58
58
|
? inputVariant
|
|
59
59
|
: defaultVariant;
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
href: disabled ? undefined : href, target: disabled ? undefined : target, rel: sanitizedRel, onClick: disabled ? undefined : onClick, color: 'inherit', weight: variant === 'action' ? 'semibold' : 'inherit', className: twMerge('focus:outline-none hover:underline leading-[inherit]', COLOR_DISABLED_MAP[color][variant][disabled ? 'disabled' : 'normal'], disabled ? 'cursor-not-allowed' : '', noUnderline ? '!no-underline' : '', visited
|
|
60
|
+
return {
|
|
61
|
+
className: twMerge('focus:outline-none hover:underline leading-[inherit]', COLOR_DISABLED_MAP[color][variant][disabled ? 'disabled' : 'normal'], disabled ? 'cursor-not-allowed' : '', noUnderline ? '!no-underline' : '', visited
|
|
63
62
|
? color === 'blue'
|
|
64
63
|
? 'visited text-purple-500'
|
|
65
64
|
: 'visited text-gray-500'
|
|
66
|
-
: '', onClick || href ? 'cursor-pointer' : '', className),
|
|
65
|
+
: '', onClick || href ? 'cursor-pointer' : '', className),
|
|
66
|
+
href: disabled ? undefined : href,
|
|
67
|
+
target: disabled ? undefined : target,
|
|
68
|
+
rel: sanitizedRel,
|
|
69
|
+
onClick: disabled ? undefined : onClick,
|
|
70
|
+
weight: variant === 'action' ? 'semibold' : 'inherit',
|
|
71
|
+
color: 'inherit',
|
|
72
|
+
style,
|
|
73
|
+
tabIndex,
|
|
74
|
+
as,
|
|
75
|
+
ariaDisabled: disabled || ariaDisabled,
|
|
76
|
+
nativeHTMLAttributes,
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
export const Link = forwardRef(function Link(props, ref) {
|
|
80
|
+
const viewModel = calculateViewModel(props);
|
|
81
|
+
return (React.createElement(Typography, Object.assign({}, viewModel.nativeHTMLAttributes, { ref: ref, as: viewModel.as,
|
|
82
|
+
// @ts-expect-error Typography is incompatible with href prop
|
|
83
|
+
href: viewModel.href, target: viewModel.target, rel: viewModel.rel, onClick: viewModel.onClick, color: viewModel.color, weight: viewModel.weight, className: viewModel.className, style: viewModel.style, tabIndex: viewModel.tabIndex, "aria-disabled": viewModel.ariaDisabled }), props.children));
|
|
67
84
|
});
|
|
68
85
|
Link.defaultProps = {
|
|
69
86
|
as: 'a',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../../src/Link/Link.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAEvD,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,CAAU,CAAA;AAClD,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAKvD,MAAM,WAAW,GAAG,CAAC,GAAuB,EAAE,MAA0B,EAAE,EAAE;IAC1E,IAAI,MAAM,KAAK,QAAQ,EAAE;QACvB,OAAO,GAAG,CAAA;KACX;IAED,IAAI,CAAC,GAAG,EAAE;QACR,OAAO,UAAU,CAAA;KAClB;IAED,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;IAExE,OAAO,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;AAClD,CAAC,CAAA;AAED,MAAM,kBAAkB,GAGpB;IACF,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,QAAQ,EAAE,2DAA2D;YACrE,MAAM,EAAE,oDAAoD;SAC7D;QACD,MAAM,EAAE;YACN,QAAQ,EAAE,yBAAyB;YACnC,MAAM,EAAE,oDAAoD;SAC7D;KACF;IACD,KAAK,EAAE;QACL,MAAM,EAAE;YACN,QAAQ,EAAE,eAAe;YACzB,MAAM,EAAE,SAAS;SAClB;QACD,MAAM,EAAE;YACN,QAAQ,EAAE,+CAA+C;YACzD,MAAM,EAAE,oDAAoD;SAC7D;KACF;CACF,CAAA;AAgCD,MAAM,YAAY,GAAG,MAAM,CAAA;AAC3B,MAAM,cAAc,GAAG,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../../src/Link/Link.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toptal/picasso-link",
|
|
3
|
-
"version": "3.0.5-alpha-
|
|
3
|
+
"version": "3.0.5-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.14+3ab759916",
|
|
4
4
|
"description": "Toptal UI components library - Link",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/toptal/picasso/tree/master/packages/picasso#readme",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@toptal/picasso-typography": "4.0.3-alpha-
|
|
26
|
-
"@toptal/picasso-utils": "3.0.1-alpha-
|
|
25
|
+
"@toptal/picasso-typography": "4.0.3-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.14+3ab759916",
|
|
26
|
+
"@toptal/picasso-utils": "3.0.1-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.14+3ab759916"
|
|
27
27
|
},
|
|
28
28
|
"sideEffects": [
|
|
29
29
|
"**/styles.ts",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
".": "./dist-package/src/index.js"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@toptal/picasso-provider": "5.0.1-alpha-
|
|
43
|
-
"@toptal/picasso-tailwind-merge": "2.0.3-alpha-
|
|
44
|
-
"@toptal/picasso-test-utils": "1.1.2-alpha-
|
|
42
|
+
"@toptal/picasso-provider": "5.0.1-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.188+3ab759916",
|
|
43
|
+
"@toptal/picasso-tailwind-merge": "2.0.3-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.14+3ab759916",
|
|
44
|
+
"@toptal/picasso-test-utils": "1.1.2-alpha-FX-NULL-do-not-pass-min-and-max-3ab759916.267+3ab759916"
|
|
45
45
|
},
|
|
46
46
|
"files": [
|
|
47
47
|
"dist-package/**",
|
|
48
48
|
"!dist-package/tsconfig.tsbuildinfo",
|
|
49
49
|
"src"
|
|
50
50
|
],
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "3ab75991614e7b60794ebca5dcc0ec8863b417b9"
|
|
52
52
|
}
|
package/src/Link/Link.tsx
CHANGED
|
@@ -83,18 +83,30 @@ export type Props = BaseProps &
|
|
|
83
83
|
const defaultColor = 'blue'
|
|
84
84
|
const defaultVariant = 'anchor'
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
type ViewModel = {
|
|
87
|
+
className: string
|
|
88
|
+
href?: string
|
|
89
|
+
target?: string
|
|
90
|
+
color?: 'inherit'
|
|
91
|
+
rel?: string
|
|
92
|
+
onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void
|
|
93
|
+
weight: 'inherit' | 'semibold'
|
|
94
|
+
style?: React.CSSProperties
|
|
95
|
+
tabIndex?: number
|
|
96
|
+
as: Props['as']
|
|
97
|
+
ariaDisabled?: boolean
|
|
98
|
+
nativeHTMLAttributes: Omit<Props, keyof BaseProps>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* eslint-disable complexity */
|
|
102
|
+
export const calculateViewModel = (props: Props): ViewModel => {
|
|
90
103
|
const {
|
|
91
104
|
href,
|
|
92
105
|
onClick,
|
|
93
|
-
children,
|
|
94
106
|
className,
|
|
107
|
+
as = 'a',
|
|
95
108
|
color: inputColor = 'blue',
|
|
96
109
|
style,
|
|
97
|
-
as = 'a',
|
|
98
110
|
variant: inputVariant = 'anchor',
|
|
99
111
|
tabIndex,
|
|
100
112
|
target,
|
|
@@ -103,9 +115,9 @@ export const Link: OverridableComponent<Props> = forwardRef<
|
|
|
103
115
|
visited = false,
|
|
104
116
|
noUnderline,
|
|
105
117
|
'aria-disabled': ariaDisabled,
|
|
106
|
-
...
|
|
118
|
+
...nativeHTMLAttributes
|
|
107
119
|
} = props
|
|
108
|
-
|
|
120
|
+
|
|
109
121
|
const sanitizedRel = sanitizeRel(rel, target)
|
|
110
122
|
|
|
111
123
|
// When Link is used as={Link}, TypeScript can't ensure the input to the Link is compatible with its Props type.
|
|
@@ -114,36 +126,58 @@ export const Link: OverridableComponent<Props> = forwardRef<
|
|
|
114
126
|
? inputVariant
|
|
115
127
|
: defaultVariant
|
|
116
128
|
|
|
129
|
+
return {
|
|
130
|
+
className: twMerge(
|
|
131
|
+
'focus:outline-none hover:underline leading-[inherit]',
|
|
132
|
+
COLOR_DISABLED_MAP[color][variant][disabled ? 'disabled' : 'normal'],
|
|
133
|
+
disabled ? 'cursor-not-allowed' : '',
|
|
134
|
+
noUnderline ? '!no-underline' : '',
|
|
135
|
+
visited
|
|
136
|
+
? color === 'blue'
|
|
137
|
+
? 'visited text-purple-500'
|
|
138
|
+
: 'visited text-gray-500'
|
|
139
|
+
: '',
|
|
140
|
+
onClick || href ? 'cursor-pointer' : '',
|
|
141
|
+
className
|
|
142
|
+
),
|
|
143
|
+
href: disabled ? undefined : href,
|
|
144
|
+
target: disabled ? undefined : target,
|
|
145
|
+
rel: sanitizedRel,
|
|
146
|
+
onClick: disabled ? undefined : onClick,
|
|
147
|
+
weight: variant === 'action' ? 'semibold' : 'inherit',
|
|
148
|
+
color: 'inherit',
|
|
149
|
+
style,
|
|
150
|
+
tabIndex,
|
|
151
|
+
as,
|
|
152
|
+
ariaDisabled: disabled || ariaDisabled,
|
|
153
|
+
nativeHTMLAttributes,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export const Link: OverridableComponent<Props> = forwardRef<
|
|
158
|
+
HTMLAnchorElement,
|
|
159
|
+
Props
|
|
160
|
+
>(function Link(props, ref) {
|
|
161
|
+
const viewModel = calculateViewModel(props)
|
|
162
|
+
|
|
117
163
|
return (
|
|
118
164
|
<Typography
|
|
119
|
-
{...nativeHTMLAttributes}
|
|
165
|
+
{...viewModel.nativeHTMLAttributes}
|
|
120
166
|
ref={ref}
|
|
121
|
-
as={as}
|
|
167
|
+
as={viewModel.as}
|
|
122
168
|
// @ts-expect-error Typography is incompatible with href prop
|
|
123
|
-
href={
|
|
124
|
-
target={
|
|
125
|
-
rel={
|
|
126
|
-
onClick={
|
|
127
|
-
color=
|
|
128
|
-
weight={
|
|
129
|
-
className={
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
noUnderline ? '!no-underline' : '',
|
|
134
|
-
visited
|
|
135
|
-
? color === 'blue'
|
|
136
|
-
? 'visited text-purple-500'
|
|
137
|
-
: 'visited text-gray-500'
|
|
138
|
-
: '',
|
|
139
|
-
onClick || href ? 'cursor-pointer' : '',
|
|
140
|
-
className
|
|
141
|
-
)}
|
|
142
|
-
style={style}
|
|
143
|
-
tabIndex={tabIndex}
|
|
144
|
-
aria-disabled={disabled || ariaDisabled}
|
|
169
|
+
href={viewModel.href}
|
|
170
|
+
target={viewModel.target}
|
|
171
|
+
rel={viewModel.rel}
|
|
172
|
+
onClick={viewModel.onClick}
|
|
173
|
+
color={viewModel.color}
|
|
174
|
+
weight={viewModel.weight}
|
|
175
|
+
className={viewModel.className}
|
|
176
|
+
style={viewModel.style}
|
|
177
|
+
tabIndex={viewModel.tabIndex}
|
|
178
|
+
aria-disabled={viewModel.ariaDisabled}
|
|
145
179
|
>
|
|
146
|
-
{children}
|
|
180
|
+
{props.children}
|
|
147
181
|
</Typography>
|
|
148
182
|
)
|
|
149
183
|
})
|
|
@@ -14,24 +14,7 @@ exports[`Link renders 1`] = `
|
|
|
14
14
|
</div>
|
|
15
15
|
`;
|
|
16
16
|
|
|
17
|
-
exports[`Link
|
|
18
|
-
<div>
|
|
19
|
-
<div
|
|
20
|
-
class="Picasso-root"
|
|
21
|
-
>
|
|
22
|
-
<div>
|
|
23
|
-
<a
|
|
24
|
-
class="m-0 font-inherit font-inherit focus:outline-none hover:underline leading-[inherit] text-blue visited:text-purple no-underline"
|
|
25
|
-
href="/"
|
|
26
|
-
>
|
|
27
|
-
Please verify your email
|
|
28
|
-
</a>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
`;
|
|
33
|
-
|
|
34
|
-
exports[`Link renders disabled link 1`] = `
|
|
17
|
+
exports[`Link when disabled renders disabled link 1`] = `
|
|
35
18
|
<div>
|
|
36
19
|
<div
|
|
37
20
|
class="Picasso-root"
|
|
@@ -48,7 +31,7 @@ exports[`Link renders disabled link 1`] = `
|
|
|
48
31
|
</div>
|
|
49
32
|
`;
|
|
50
33
|
|
|
51
|
-
exports[`Link renders native attributes 1`] = `
|
|
34
|
+
exports[`Link when native attributes are provided renders native attributes 1`] = `
|
|
52
35
|
<div>
|
|
53
36
|
<div
|
|
54
37
|
class="Picasso-root"
|
|
@@ -65,3 +48,20 @@ exports[`Link renders native attributes 1`] = `
|
|
|
65
48
|
</div>
|
|
66
49
|
</div>
|
|
67
50
|
`;
|
|
51
|
+
|
|
52
|
+
exports[`Link when using react-router Link renders a Link from react-router 1`] = `
|
|
53
|
+
<div>
|
|
54
|
+
<div
|
|
55
|
+
class="Picasso-root"
|
|
56
|
+
>
|
|
57
|
+
<div>
|
|
58
|
+
<a
|
|
59
|
+
class="m-0 font-inherit font-inherit focus:outline-none hover:underline leading-[inherit] text-blue visited:text-purple no-underline"
|
|
60
|
+
href="/"
|
|
61
|
+
>
|
|
62
|
+
Please verify your email
|
|
63
|
+
</a>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
`;
|
package/src/Link/test.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { render, fireEvent } from '@toptal/picasso-test-utils'
|
|
3
3
|
import { MemoryRouter, Link as RouterLink } from 'react-router-dom'
|
|
4
4
|
|
|
5
|
+
import { calculateViewModel } from './Link'
|
|
5
6
|
import { Link } from '../Link'
|
|
6
7
|
|
|
7
8
|
describe('Link', () => {
|
|
@@ -11,91 +12,335 @@ describe('Link', () => {
|
|
|
11
12
|
expect(container).toMatchSnapshot()
|
|
12
13
|
})
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
describe('when native attributes are provided', () => {
|
|
16
|
+
it('renders native attributes', () => {
|
|
17
|
+
const { container } = render(
|
|
18
|
+
<Link
|
|
19
|
+
onBlur={() => window.alert('onBlur')}
|
|
20
|
+
rel='noopener'
|
|
21
|
+
target='_blank'
|
|
22
|
+
download='filename'
|
|
23
|
+
href='https://toptal.com/filename.txt'
|
|
24
|
+
>
|
|
25
|
+
Please verify your email
|
|
26
|
+
</Link>
|
|
27
|
+
)
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
expect(container).toMatchSnapshot()
|
|
30
|
+
})
|
|
28
31
|
})
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
describe('when using react-router Link', () => {
|
|
34
|
+
it('renders a Link from react-router', () => {
|
|
35
|
+
const { container } = render(
|
|
36
|
+
<MemoryRouter>
|
|
37
|
+
<div>
|
|
38
|
+
<Link as={RouterLink} to='/'>
|
|
39
|
+
Please verify your email
|
|
40
|
+
</Link>
|
|
41
|
+
</div>
|
|
42
|
+
</MemoryRouter>
|
|
43
|
+
)
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
expect(container).toMatchSnapshot()
|
|
46
|
+
})
|
|
42
47
|
})
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
describe('when disabled', () => {
|
|
50
|
+
it('renders disabled link', () => {
|
|
51
|
+
const { container } = render(
|
|
52
|
+
<Link
|
|
53
|
+
rel='noopener'
|
|
54
|
+
target='_blank'
|
|
55
|
+
download='filename'
|
|
56
|
+
href='https://toptal.com/filename.txt'
|
|
57
|
+
disabled
|
|
58
|
+
>
|
|
59
|
+
Please verify your email
|
|
60
|
+
</Link>
|
|
61
|
+
)
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
expect(container).toMatchSnapshot()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('does not allow onClick', () => {
|
|
67
|
+
const onClick = jest.fn()
|
|
68
|
+
const { getByTestId } = render(
|
|
69
|
+
<Link
|
|
70
|
+
data-testid='foo'
|
|
71
|
+
onClick={onClick}
|
|
72
|
+
href='https://foo.bar'
|
|
73
|
+
disabled
|
|
74
|
+
>
|
|
75
|
+
Test
|
|
76
|
+
</Link>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
fireEvent.click(getByTestId('foo'))
|
|
80
|
+
expect(onClick).not.toHaveBeenCalled()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('does not have href', () => {
|
|
84
|
+
const { getByTestId } = render(
|
|
85
|
+
<Link data-testid='foo' href='https://foo.bar' disabled>
|
|
86
|
+
Test
|
|
87
|
+
</Link>
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
expect(getByTestId('foo')).not.toHaveAttribute('href')
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('when target="_blank"', () => {
|
|
95
|
+
it('adds rel="noopener" if rel is absent', () => {
|
|
96
|
+
render(
|
|
97
|
+
<Link href='http://example.com' target='_blank'>
|
|
98
|
+
External Link
|
|
99
|
+
</Link>
|
|
100
|
+
)
|
|
101
|
+
expect(document.querySelector('a')).toHaveAttribute('rel', 'noopener')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('does not add rel="noopener" if noreferrer is present', () => {
|
|
105
|
+
render(
|
|
106
|
+
<Link href='http://example.com' target='_blank' rel='noreferrer'>
|
|
107
|
+
External Link
|
|
108
|
+
</Link>
|
|
109
|
+
)
|
|
110
|
+
expect(document.querySelector('a')).not.toHaveAttribute('rel', 'noopener')
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('calculateViewModel', () => {
|
|
116
|
+
describe('when no props are provided', () => {
|
|
117
|
+
it('applies default values', () => {
|
|
118
|
+
const props = {}
|
|
119
|
+
const result = calculateViewModel(props)
|
|
120
|
+
|
|
121
|
+
expect(result.className).toContain('text-blue-500')
|
|
122
|
+
expect(result.href).toBeUndefined()
|
|
123
|
+
expect(result.target).toBeUndefined()
|
|
124
|
+
expect(result.rel).toBeUndefined()
|
|
125
|
+
expect(result.onClick).toBeUndefined()
|
|
126
|
+
expect(result.weight).toBe('inherit')
|
|
127
|
+
expect(result.ariaDisabled).toBeUndefined()
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
describe('when href, target and onClick are provided', () => {
|
|
132
|
+
it('passes them through to view model', () => {
|
|
133
|
+
const props = {
|
|
134
|
+
href: 'https://example.com',
|
|
135
|
+
target: '_blank',
|
|
136
|
+
onClick: jest.fn(),
|
|
137
|
+
}
|
|
138
|
+
const result = calculateViewModel(props)
|
|
139
|
+
|
|
140
|
+
expect(result.href).toBe('https://example.com')
|
|
141
|
+
expect(result.target).toBe('_blank')
|
|
142
|
+
expect(result.onClick).toBe(props.onClick)
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
describe('when target="_blank" and rel is provided', () => {
|
|
147
|
+
it('sanitizes rel for target="_blank"', () => {
|
|
148
|
+
const props = {
|
|
149
|
+
target: '_blank',
|
|
150
|
+
rel: 'nofollow',
|
|
151
|
+
}
|
|
152
|
+
const result = calculateViewModel(props)
|
|
153
|
+
|
|
154
|
+
expect(result.rel).toBe('nofollow noopener')
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
describe('when disabled', () => {
|
|
159
|
+
it('applies disabled behavior', () => {
|
|
160
|
+
const props = {
|
|
161
|
+
disabled: true,
|
|
162
|
+
href: 'https://example.com',
|
|
163
|
+
target: '_blank',
|
|
164
|
+
onClick: jest.fn(),
|
|
165
|
+
}
|
|
166
|
+
const result = calculateViewModel(props)
|
|
167
|
+
|
|
168
|
+
expect(result.className).toContain('cursor-pointer')
|
|
169
|
+
expect(result.href).toBeUndefined()
|
|
170
|
+
expect(result.target).toBeUndefined()
|
|
171
|
+
expect(result.onClick).toBeUndefined()
|
|
172
|
+
expect(result.ariaDisabled).toBe(true)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('applies disabled color styles for the provided color', () => {
|
|
176
|
+
const blueProps = {
|
|
177
|
+
color: 'blue',
|
|
178
|
+
disabled: true,
|
|
179
|
+
}
|
|
180
|
+
const whiteProps = {
|
|
181
|
+
color: 'white',
|
|
182
|
+
disabled: true,
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const blueResult = calculateViewModel(blueProps)
|
|
186
|
+
const whiteResult = calculateViewModel(whiteProps)
|
|
187
|
+
|
|
188
|
+
expect(blueResult.className).toContain(
|
|
189
|
+
'focus:outline-none hover:underline leading-[inherit] text-gray-600 underline cursor-not-allowed'
|
|
190
|
+
)
|
|
191
|
+
expect(whiteResult.className).toContain('text-gray-600')
|
|
192
|
+
})
|
|
58
193
|
})
|
|
59
194
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
195
|
+
describe('when visited is true', () => {
|
|
196
|
+
it('applies visited class when color is blue', () => {
|
|
197
|
+
const props = {
|
|
198
|
+
visited: true,
|
|
199
|
+
color: 'blue',
|
|
200
|
+
}
|
|
201
|
+
const result = calculateViewModel(props)
|
|
66
202
|
|
|
67
|
-
|
|
203
|
+
expect(result.className).toContain('visited text-purple-500')
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it('applies visited class when color is white', () => {
|
|
207
|
+
const props = {
|
|
208
|
+
color: 'white',
|
|
209
|
+
visited: true,
|
|
210
|
+
}
|
|
211
|
+
const result = calculateViewModel(props)
|
|
212
|
+
|
|
213
|
+
expect(result.className).toContain('visited text-gray-500')
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
describe('when noUnderline is true', () => {
|
|
218
|
+
it('handles noUnderline properly', () => {
|
|
219
|
+
const props = {
|
|
220
|
+
noUnderline: true,
|
|
221
|
+
color: 'blue',
|
|
222
|
+
}
|
|
223
|
+
const result = calculateViewModel(props)
|
|
224
|
+
|
|
225
|
+
expect(result.className).toContain('!no-underline')
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
describe('when variant is provided', () => {
|
|
230
|
+
it('applies correct weight based on variant', () => {
|
|
231
|
+
const actionProps = {
|
|
232
|
+
variant: 'action' as const,
|
|
233
|
+
}
|
|
234
|
+
const anchorProps = {
|
|
235
|
+
variant: 'anchor' as const,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const actionResult = calculateViewModel(actionProps)
|
|
239
|
+
const anchorResult = calculateViewModel(anchorProps)
|
|
240
|
+
|
|
241
|
+
expect(actionResult.weight).toBe('semibold')
|
|
242
|
+
expect(anchorResult.weight).toBe('inherit')
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
describe('when unsupported color or variant is provided', () => {
|
|
247
|
+
it('uses default values', () => {
|
|
248
|
+
const props = {
|
|
249
|
+
color: 'unsupportedColor',
|
|
250
|
+
variant: 'unsupportedVariant',
|
|
251
|
+
}
|
|
252
|
+
const result = calculateViewModel(props)
|
|
253
|
+
|
|
254
|
+
expect(result.className).toContain('text-blue-500')
|
|
255
|
+
expect(result.weight).toBe('inherit')
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
describe('when className is provided', () => {
|
|
260
|
+
it('applies custom className', () => {
|
|
261
|
+
const props = {
|
|
262
|
+
className: 'custom-class',
|
|
263
|
+
}
|
|
264
|
+
const result = calculateViewModel(props)
|
|
265
|
+
|
|
266
|
+
expect(result.className).toContain('custom-class')
|
|
267
|
+
})
|
|
68
268
|
})
|
|
69
269
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
270
|
+
describe('when tabIndex is provided', () => {
|
|
271
|
+
it('applies tabIndex', () => {
|
|
272
|
+
const props = {
|
|
273
|
+
tabIndex: 0,
|
|
274
|
+
}
|
|
275
|
+
const result = calculateViewModel(props)
|
|
76
276
|
|
|
77
|
-
|
|
277
|
+
expect(result.tabIndex).toBe(0)
|
|
278
|
+
})
|
|
78
279
|
})
|
|
79
280
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
)
|
|
281
|
+
describe('when additional native HTML attributes are provided', () => {
|
|
282
|
+
it('includes them', () => {
|
|
283
|
+
const props = {
|
|
284
|
+
'data-test-id': 'link-element',
|
|
285
|
+
}
|
|
286
|
+
const result = calculateViewModel(props)
|
|
87
287
|
|
|
88
|
-
|
|
89
|
-
|
|
288
|
+
expect(result.nativeHTMLAttributes['data-test-id']).toBe('link-element')
|
|
289
|
+
})
|
|
90
290
|
})
|
|
91
291
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
292
|
+
describe('when "as" prop is provided', () => {
|
|
293
|
+
it('applies the default "as" prop as "a" when no "as" prop is provided', () => {
|
|
294
|
+
const props = {}
|
|
295
|
+
const result = calculateViewModel(props)
|
|
296
|
+
|
|
297
|
+
expect(result.as).toBe('a')
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
it('applies the provided "as" prop when a custom element type is given', () => {
|
|
301
|
+
const props = {
|
|
302
|
+
as: 'button',
|
|
303
|
+
}
|
|
304
|
+
const result = calculateViewModel(props)
|
|
305
|
+
|
|
306
|
+
expect(result.as).toBe('button')
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
it('applies the provided "as" prop with a custom React component', () => {
|
|
310
|
+
const CustomComponent = () => <div />
|
|
311
|
+
const props = {
|
|
312
|
+
as: CustomComponent,
|
|
313
|
+
}
|
|
314
|
+
const result = calculateViewModel(props)
|
|
315
|
+
|
|
316
|
+
expect(result.as).toBe(CustomComponent)
|
|
317
|
+
})
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
describe('when color prop is provided', () => {
|
|
321
|
+
it('applies the default color "blue" when no color prop is provided', () => {
|
|
322
|
+
const props = {}
|
|
323
|
+
const result = calculateViewModel(props)
|
|
324
|
+
|
|
325
|
+
expect(result.className).toContain('text-blue-500')
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
it('applies the white color when color="white" is provided', () => {
|
|
329
|
+
const props = {
|
|
330
|
+
color: 'white',
|
|
331
|
+
}
|
|
332
|
+
const result = calculateViewModel(props)
|
|
333
|
+
|
|
334
|
+
expect(result.className).toContain('inherit')
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('fallbacks to the default color "blue" if an unsupported color is provided', () => {
|
|
338
|
+
const props = {
|
|
339
|
+
color: 'unsupportedColor',
|
|
340
|
+
}
|
|
341
|
+
const result = calculateViewModel(props)
|
|
98
342
|
|
|
99
|
-
|
|
343
|
+
expect(result.className).toContain('text-blue-500')
|
|
344
|
+
})
|
|
100
345
|
})
|
|
101
346
|
})
|