@instructure/ui-link 11.6.0 → 11.6.1-snapshot-129
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/CHANGELOG.md +40 -288
- package/es/Link/{index.js → v1/index.js} +2 -2
- package/es/Link/v2/index.js +253 -0
- package/es/Link/v2/props.js +26 -0
- package/es/Link/v2/styles.js +242 -0
- package/es/{index.js → exports/a.js} +1 -1
- package/{src/index.ts → es/exports/b.js} +1 -3
- package/lib/Link/{index.js → v1/index.js} +3 -3
- package/lib/Link/v2/index.js +262 -0
- package/lib/Link/v2/props.js +31 -0
- package/lib/Link/v2/styles.js +248 -0
- package/lib/{index.js → exports/a.js} +2 -2
- package/lib/exports/b.js +12 -0
- package/package.json +43 -21
- package/src/Link/{index.tsx → v1/index.tsx} +3 -3
- package/src/Link/{props.ts → v1/props.ts} +1 -1
- package/src/Link/v2/README.md +261 -0
- package/src/Link/v2/index.tsx +321 -0
- package/src/Link/v2/props.ts +184 -0
- package/src/Link/v2/styles.ts +267 -0
- package/src/exports/a.ts +26 -0
- package/src/exports/b.ts +26 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Link/{index.d.ts → v1/index.d.ts} +1 -1
- package/types/Link/v1/index.d.ts.map +1 -0
- package/types/Link/{props.d.ts → v1/props.d.ts} +1 -1
- package/types/Link/v1/props.d.ts.map +1 -0
- package/types/Link/v1/styles.d.ts.map +1 -0
- package/types/Link/v1/theme.d.ts.map +1 -0
- package/types/Link/v2/index.d.ts +66 -0
- package/types/Link/v2/index.d.ts.map +1 -0
- package/types/Link/v2/props.d.ts +105 -0
- package/types/Link/v2/props.d.ts.map +1 -0
- package/types/Link/v2/styles.d.ts +19 -0
- package/types/Link/v2/styles.d.ts.map +1 -0
- package/types/exports/a.d.ts +3 -0
- package/types/exports/a.d.ts.map +1 -0
- package/types/exports/b.d.ts +3 -0
- package/types/exports/b.d.ts.map +1 -0
- package/types/Link/index.d.ts.map +0 -1
- package/types/Link/props.d.ts.map +0 -1
- package/types/Link/styles.d.ts.map +0 -1
- package/types/Link/theme.d.ts.map +0 -1
- package/types/index.d.ts +0 -3
- package/types/index.d.ts.map +0 -1
- /package/es/Link/{props.js → v1/props.js} +0 -0
- /package/es/Link/{styles.js → v1/styles.js} +0 -0
- /package/es/Link/{theme.js → v1/theme.js} +0 -0
- /package/lib/Link/{props.js → v1/props.js} +0 -0
- /package/lib/Link/{styles.js → v1/styles.js} +0 -0
- /package/lib/Link/{theme.js → v1/theme.js} +0 -0
- /package/src/Link/{README.md → v1/README.md} +0 -0
- /package/src/Link/{styles.ts → v1/styles.ts} +0 -0
- /package/src/Link/{theme.ts → v1/theme.ts} +0 -0
- /package/types/Link/{styles.d.ts → v1/styles.d.ts} +0 -0
- /package/types/Link/{theme.d.ts → v1/theme.d.ts} +0 -0
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
import { Children, Component } from 'react'
|
|
26
26
|
|
|
27
|
-
import { View } from '@instructure/ui-view'
|
|
27
|
+
import { View } from '@instructure/ui-view/v11_6'
|
|
28
28
|
import { hasVisibleChildren } from '@instructure/ui-a11y-utils'
|
|
29
29
|
import { isActiveElement, findFocusable } from '@instructure/ui-dom-utils'
|
|
30
30
|
import {
|
|
@@ -37,14 +37,14 @@ import {
|
|
|
37
37
|
import { combineDataCid } from '@instructure/ui-utils'
|
|
38
38
|
import { logWarn as warn } from '@instructure/console'
|
|
39
39
|
|
|
40
|
-
import { withStyle } from '@instructure/emotion'
|
|
40
|
+
import { withStyleLegacy as withStyle } from '@instructure/emotion'
|
|
41
41
|
import generateStyle from './styles'
|
|
42
42
|
import generateComponentTheme from './theme'
|
|
43
43
|
|
|
44
44
|
import { allowedProps } from './props'
|
|
45
45
|
import type { LinkProps, LinkState, LinkStyleProps } from './props'
|
|
46
46
|
|
|
47
|
-
import type { ViewOwnProps } from '@instructure/ui-view'
|
|
47
|
+
import type { ViewOwnProps } from '@instructure/ui-view/v11_6'
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
---
|
|
@@ -34,7 +34,7 @@ import type {
|
|
|
34
34
|
WithStyleProps,
|
|
35
35
|
ComponentStyle
|
|
36
36
|
} from '@instructure/emotion'
|
|
37
|
-
import type { ViewOwnProps } from '@instructure/ui-view'
|
|
37
|
+
import type { ViewOwnProps } from '@instructure/ui-view/v11_6'
|
|
38
38
|
import { Renderable } from '@instructure/shared-types'
|
|
39
39
|
|
|
40
40
|
type LinkOwnProps = {
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
describes: Link
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
### Where to use Link
|
|
6
|
+
|
|
7
|
+
`Link` is intended for presenting actions **inline with other content**, such as within headings or sentences. Typically those actions navigate the user to a different view.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
---
|
|
11
|
+
type: example
|
|
12
|
+
---
|
|
13
|
+
<Link href="https://instructure.github.io/instructure-ui/" target="_blank">
|
|
14
|
+
Link text
|
|
15
|
+
</Link>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Controlled navigation
|
|
19
|
+
|
|
20
|
+
Sometimes a simple `Link (<a>)` with an `href` is not enough for navigation and an `onClick` handler is needed. In this case, the recommended approach is the following
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
---
|
|
24
|
+
type: example
|
|
25
|
+
---
|
|
26
|
+
<Link
|
|
27
|
+
variant="standalone"
|
|
28
|
+
onClick = {(e)=>{
|
|
29
|
+
e.preventDefault()
|
|
30
|
+
console.log("do navigation")
|
|
31
|
+
}}
|
|
32
|
+
forceButtonRole={false}
|
|
33
|
+
href="#">Go to places
|
|
34
|
+
</Link>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If neither `href` nor `onClick` is provided, the Link will render as plain text (a `<span>` element) without interactive styling:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
---
|
|
41
|
+
type: example
|
|
42
|
+
---
|
|
43
|
+
<div>
|
|
44
|
+
<Text>This is a Link with no href or onClick: <Link>I look like plain text</Link></Text>
|
|
45
|
+
</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Size
|
|
49
|
+
|
|
50
|
+
The `size` prop controls the font size, line height, and icon size, icon gap. Available sizes are `small`, `medium`, and `large`.
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
---
|
|
54
|
+
type: example
|
|
55
|
+
---
|
|
56
|
+
<div>
|
|
57
|
+
<div>
|
|
58
|
+
<Link renderIcon={<DiamondInstUIIcon />} variant="standalone" href="https://instructure.github.io/instructure-ui/" size="small">
|
|
59
|
+
Link small
|
|
60
|
+
</Link>
|
|
61
|
+
</div>
|
|
62
|
+
<br />
|
|
63
|
+
<div>
|
|
64
|
+
<Link renderIcon={<DiamondInstUIIcon />} variant="standalone" href="https://instructure.github.io/instructure-ui/" size="medium">
|
|
65
|
+
Link medium
|
|
66
|
+
</Link>
|
|
67
|
+
</div>
|
|
68
|
+
<br />
|
|
69
|
+
<div>
|
|
70
|
+
<Link renderIcon={<DiamondInstUIIcon />} variant="standalone" href="https://instructure.github.io/instructure-ui/" size="large">
|
|
71
|
+
Link large
|
|
72
|
+
</Link>
|
|
73
|
+
</div>
|
|
74
|
+
<br />
|
|
75
|
+
</div>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Variant
|
|
79
|
+
|
|
80
|
+
The `variant` prop controls the text decoration and intended use case. Available variants are `inline` (underlined, for use within text) and `standalone` (no underline, for standalone links).
|
|
81
|
+
|
|
82
|
+
Use the `variant` prop in combination with the `size` prop to control both the appearance and size of the link.
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
---
|
|
86
|
+
type: example
|
|
87
|
+
---
|
|
88
|
+
<div>
|
|
89
|
+
<div>
|
|
90
|
+
In a line of text you should use the <Link variant="inline" size="medium" renderIcon={<DiamondInstUIIcon />} href="https://instructure.github.io/instructure-ui/">inline</Link> link variant.
|
|
91
|
+
</div>
|
|
92
|
+
<br />
|
|
93
|
+
<div>
|
|
94
|
+
If the link is standalone (not in a text), use the <code>standalone</code> variant:
|
|
95
|
+
<Link variant="standalone" size="medium" renderIcon={<DiamondInstUIIcon />} href="https://instructure.github.io/instructure-ui/">standalone</Link>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Deprecated variant values
|
|
101
|
+
|
|
102
|
+
**The following variant values are deprecated and will be removed in a future version:**
|
|
103
|
+
|
|
104
|
+
- `inline-small`
|
|
105
|
+
- `standalone-small`
|
|
106
|
+
|
|
107
|
+
These deprecated values are still supported for backward compatibility but will trigger console warnings. Please update your code to use the new `variant` + `size` prop combination.
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
---
|
|
111
|
+
type: code
|
|
112
|
+
---
|
|
113
|
+
// Deprecated (still works but triggers warning)
|
|
114
|
+
<Link variant="inline-small" href="#">Link</Link>
|
|
115
|
+
<Link variant="standalone-small" href="#">Link</Link>
|
|
116
|
+
|
|
117
|
+
// Recommended
|
|
118
|
+
<Link variant="inline" size="small" href="#">Link</Link>
|
|
119
|
+
<Link variant="standalone" size="small" href="#">Link</Link>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Adding margin
|
|
123
|
+
|
|
124
|
+
Use the `margin` prop to add space to the left or right of the Link. Because
|
|
125
|
+
Link displays `inline`, **top and bottom margin will not work**. If you need
|
|
126
|
+
to add margin to the top or bottom of Link, wrap it inside a `<View />`.
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
---
|
|
130
|
+
type: example
|
|
131
|
+
---
|
|
132
|
+
<Text>The quick brown fox <Link href="https://instructure.github.io/instructure-ui/" margin="0 small">jumps</Link> over the lazy dog.</Text>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Truncating text
|
|
136
|
+
|
|
137
|
+
Use [TruncateText](TruncateText) to truncate text within Link. Note this will cause Link to display `inline-flex`,
|
|
138
|
+
unless an alternate `display` prop is provided.
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
---
|
|
142
|
+
type: example
|
|
143
|
+
---
|
|
144
|
+
<Link
|
|
145
|
+
onClick={() => console.log('clicked')}
|
|
146
|
+
renderIcon={<DiamondInstUIIcon />}
|
|
147
|
+
>
|
|
148
|
+
<TruncateText>{lorem.paragraph()}</TruncateText>
|
|
149
|
+
</Link>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Using icons
|
|
153
|
+
|
|
154
|
+
Use the `renderIcon` property to put an [icon](icons) inside a Link. To position the
|
|
155
|
+
icon _after_ the link text, change the `iconPlacement` property to `end`. You can also
|
|
156
|
+
render a Link with just an icon. Don't forget to add text for screen readers, though.
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
---
|
|
160
|
+
type: example
|
|
161
|
+
---
|
|
162
|
+
<div>
|
|
163
|
+
<View as="div" margin="0 0 small">
|
|
164
|
+
<Link href="https://instructure.design" renderIcon={<DiamondInstUIIcon />}>Icon before text</Link> with the quick brown fox
|
|
165
|
+
</View>
|
|
166
|
+
<View as="div" margin="0 0 small">
|
|
167
|
+
This Link has an icon and displays inline with text. <Link
|
|
168
|
+
href="https://instructure.design"
|
|
169
|
+
renderIcon={<DiamondInstUIIcon />}
|
|
170
|
+
iconPlacement="end"
|
|
171
|
+
>
|
|
172
|
+
Icon appears after Link text
|
|
173
|
+
</Link>. This is more text after the link.
|
|
174
|
+
</View>
|
|
175
|
+
<View as="div">
|
|
176
|
+
This Link consists of only an icon
|
|
177
|
+
<Link onClick={() => console.log('clicked!')} renderIcon={<DiamondInstUIIcon />}>
|
|
178
|
+
<ScreenReaderContent>Descriptive text</ScreenReaderContent>
|
|
179
|
+
</Link>.
|
|
180
|
+
</View>
|
|
181
|
+
</div>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Theme overrides
|
|
185
|
+
|
|
186
|
+
Examples showing how [theme overrides](using-theme-overrides) work for Link:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
---
|
|
190
|
+
type: example
|
|
191
|
+
---
|
|
192
|
+
<div>
|
|
193
|
+
<InstUISettingsProvider
|
|
194
|
+
theme={{
|
|
195
|
+
newTheme: {
|
|
196
|
+
sharedTokens: {
|
|
197
|
+
focusOutline: {
|
|
198
|
+
infoColor: 'pink',
|
|
199
|
+
width: '0.5rem',
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
<Text>The quick brown fox <Link
|
|
206
|
+
href="https://instructure.github.io/instructure-ui/"
|
|
207
|
+
themeOverride={{
|
|
208
|
+
textColor: 'red',
|
|
209
|
+
textHoverColor: 'green',
|
|
210
|
+
fontWeight: 700
|
|
211
|
+
}}>jumps</Link> over the lazy dog.
|
|
212
|
+
</Text>
|
|
213
|
+
</InstUISettingsProvider>
|
|
214
|
+
</div>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
---
|
|
219
|
+
type: example
|
|
220
|
+
---
|
|
221
|
+
<View background="primary-inverse" as="div">
|
|
222
|
+
<Text color="primary-inverse">The quick brown fox <Link
|
|
223
|
+
href="https://instructure.github.io/instructure-ui/"
|
|
224
|
+
color="link"
|
|
225
|
+
themeOverride={{
|
|
226
|
+
textColor: 'red',
|
|
227
|
+
textHoverColor: 'magenta',
|
|
228
|
+
onColorTextColor: 'orange',
|
|
229
|
+
onColorTextHoverColor: 'lime',
|
|
230
|
+
fontWeight: 700
|
|
231
|
+
}}
|
|
232
|
+
>jumps</Link> over the lazy dog.</Text>
|
|
233
|
+
<br />
|
|
234
|
+
<Text color="primary-inverse">The quick brown fox <Link
|
|
235
|
+
href="https://instructure.github.io/instructure-ui/"
|
|
236
|
+
renderIcon={<LogOutInstUIIcon />}
|
|
237
|
+
color="link-inverse"
|
|
238
|
+
themeOverride={{
|
|
239
|
+
textColor: 'red',
|
|
240
|
+
textHoverColor: 'magenta',
|
|
241
|
+
onColorTextColor: 'orange',
|
|
242
|
+
onColorTextHoverColor: 'lime',
|
|
243
|
+
fontWeight: 700
|
|
244
|
+
}}
|
|
245
|
+
>jumps</Link> over the lazy dog.</Text>
|
|
246
|
+
</View>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Guidelines
|
|
250
|
+
|
|
251
|
+
```js
|
|
252
|
+
---
|
|
253
|
+
type: embed
|
|
254
|
+
---
|
|
255
|
+
<Guidelines>
|
|
256
|
+
<Figure recommendation="a11y" title="Accessibility">
|
|
257
|
+
<Figure.Item>Use <code>color="link-inverse"</code> when a Link appears on a dark background to ensure adequate contrast</Figure.Item>
|
|
258
|
+
<Figure.Item>Links must have a non-empty href attribute to be considered true links and to be accessible to keyboard users</Figure.Item>
|
|
259
|
+
</Figure>
|
|
260
|
+
</Guidelines>
|
|
261
|
+
```
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The MIT License (MIT)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2015 - present Instructure, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { Children, Component } from 'react'
|
|
26
|
+
|
|
27
|
+
import { View } from '@instructure/ui-view/latest'
|
|
28
|
+
import { hasVisibleChildren } from '@instructure/ui-a11y-utils'
|
|
29
|
+
import { isActiveElement, findFocusable } from '@instructure/ui-dom-utils'
|
|
30
|
+
import {
|
|
31
|
+
getElementType,
|
|
32
|
+
getInteraction,
|
|
33
|
+
matchComponentTypes,
|
|
34
|
+
passthroughProps
|
|
35
|
+
} from '@instructure/ui-react-utils'
|
|
36
|
+
import { combineDataCid } from '@instructure/ui-utils'
|
|
37
|
+
import { logWarn as warn } from '@instructure/console'
|
|
38
|
+
import { renderIconWithProps } from '@instructure/ui-icons'
|
|
39
|
+
|
|
40
|
+
import { withStyle } from '@instructure/emotion'
|
|
41
|
+
import generateStyle from './styles'
|
|
42
|
+
|
|
43
|
+
import { allowedProps } from './props'
|
|
44
|
+
import type { LinkProps, LinkState, LinkStyleProps } from './props'
|
|
45
|
+
|
|
46
|
+
import type { ViewOwnProps } from '@instructure/ui-view/latest'
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
---
|
|
50
|
+
category: components
|
|
51
|
+
---
|
|
52
|
+
**/
|
|
53
|
+
@withStyle(generateStyle)
|
|
54
|
+
class Link extends Component<LinkProps, LinkState> {
|
|
55
|
+
static readonly componentId = 'Link'
|
|
56
|
+
|
|
57
|
+
static allowedProps = allowedProps
|
|
58
|
+
static defaultProps = {
|
|
59
|
+
// Leave interaction default undefined so that `disabled` can also be supplied
|
|
60
|
+
interaction: undefined,
|
|
61
|
+
color: 'link',
|
|
62
|
+
iconPlacement: 'start',
|
|
63
|
+
forceButtonRole: true
|
|
64
|
+
} as const
|
|
65
|
+
|
|
66
|
+
state = { hasFocus: false }
|
|
67
|
+
|
|
68
|
+
get _link() {
|
|
69
|
+
console.warn(
|
|
70
|
+
'_link property is deprecated and will be removed in v9, please use ref instead'
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
return this.ref
|
|
74
|
+
}
|
|
75
|
+
ref: Element | null = null
|
|
76
|
+
|
|
77
|
+
componentDidMount() {
|
|
78
|
+
this.props.makeStyles?.(this.makeStyleProps())
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
componentDidUpdate() {
|
|
82
|
+
this.props.makeStyles?.(this.makeStyleProps())
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
makeStyleProps = (): LinkStyleProps & {
|
|
86
|
+
variant?: LinkProps['variant']
|
|
87
|
+
size?: LinkProps['size']
|
|
88
|
+
} => {
|
|
89
|
+
const { variant: variantProp, size: sizeProp } = this.props
|
|
90
|
+
|
|
91
|
+
// Handle deprecated variant values by mapping them to new variant + size props
|
|
92
|
+
let variant: 'inline' | 'standalone' | undefined = variantProp as any
|
|
93
|
+
let size = sizeProp
|
|
94
|
+
|
|
95
|
+
if (variantProp === 'inline-small' || variantProp === 'standalone-small') {
|
|
96
|
+
warn(
|
|
97
|
+
false,
|
|
98
|
+
`[Link] The variant value "${variantProp}" is deprecated. Use variant="${variantProp.replace(
|
|
99
|
+
'-small',
|
|
100
|
+
''
|
|
101
|
+
)}" with size="small" instead.`
|
|
102
|
+
)
|
|
103
|
+
variant = variantProp.replace('-small', '') as 'inline' | 'standalone'
|
|
104
|
+
// Only set size from deprecated variant if size prop is not explicitly provided
|
|
105
|
+
if (!sizeProp) {
|
|
106
|
+
size = 'small'
|
|
107
|
+
}
|
|
108
|
+
} else if (
|
|
109
|
+
(variantProp === 'inline' || variantProp === 'standalone') &&
|
|
110
|
+
!sizeProp
|
|
111
|
+
) {
|
|
112
|
+
// When using new variant values without explicit size, default to medium
|
|
113
|
+
// This maintains the old behavior where 'inline' and 'standalone' were medium-sized
|
|
114
|
+
size = 'medium'
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
containsTruncateText: this.containsTruncateText,
|
|
119
|
+
hasVisibleChildren: this.hasVisibleChildren,
|
|
120
|
+
variant,
|
|
121
|
+
size
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
handleElementRef = (el: Element | null) => {
|
|
126
|
+
const { elementRef } = this.props
|
|
127
|
+
|
|
128
|
+
this.ref = el
|
|
129
|
+
|
|
130
|
+
if (typeof elementRef === 'function') {
|
|
131
|
+
elementRef(el)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
handleClick: React.MouseEventHandler<ViewOwnProps> = (event) => {
|
|
136
|
+
const { onClick } = this.props
|
|
137
|
+
const { interaction } = this
|
|
138
|
+
|
|
139
|
+
if (interaction === 'disabled') {
|
|
140
|
+
event.preventDefault()
|
|
141
|
+
event.stopPropagation()
|
|
142
|
+
} else if (typeof onClick === 'function') {
|
|
143
|
+
onClick(event)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
handleFocus: React.FocusEventHandler<ViewOwnProps> = (event) => {
|
|
148
|
+
this.setState({ hasFocus: true })
|
|
149
|
+
if (typeof this.props.onFocus === 'function') {
|
|
150
|
+
this.props.onFocus(event)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
handleBlur: React.FocusEventHandler<ViewOwnProps> = (event) => {
|
|
155
|
+
this.setState({ hasFocus: false })
|
|
156
|
+
if (typeof this.props.onBlur === 'function') {
|
|
157
|
+
this.props.onBlur(event)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get containsTruncateText() {
|
|
162
|
+
let truncateText = false
|
|
163
|
+
|
|
164
|
+
Children.forEach(this.props.children, (child) => {
|
|
165
|
+
if (child && matchComponentTypes(child, ['TruncateText'])) {
|
|
166
|
+
truncateText = true
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
warn(
|
|
171
|
+
// if display prop is used, warn about icon or TruncateText
|
|
172
|
+
!truncateText || this.props.display === undefined,
|
|
173
|
+
'[Link] Using the display property with TruncateText may cause layout issues.'
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return truncateText
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
get display() {
|
|
180
|
+
if (this.props.display) {
|
|
181
|
+
return this.props.display // user-entered display property
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const { containsTruncateText } = this
|
|
185
|
+
|
|
186
|
+
if (this.props.renderIcon) {
|
|
187
|
+
return containsTruncateText ? 'inline-flex' : 'inline-block'
|
|
188
|
+
} else {
|
|
189
|
+
return containsTruncateText ? 'block' : 'auto'
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
get interaction() {
|
|
194
|
+
return getInteraction({ props: this.props, interactionTypes: ['disabled'] })
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
get element() {
|
|
198
|
+
return getElementType(Link, this.props)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get focused() {
|
|
202
|
+
return isActiveElement(this.ref)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
get focusable() {
|
|
206
|
+
return findFocusable(this.ref)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
get hasVisibleChildren() {
|
|
210
|
+
return hasVisibleChildren(this.props.children)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
get role() {
|
|
214
|
+
const { role, forceButtonRole, onClick } = this.props
|
|
215
|
+
|
|
216
|
+
if (forceButtonRole) {
|
|
217
|
+
return onClick && this.element !== 'button' ? 'button' : role
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return role
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
focus() {
|
|
224
|
+
this.ref && (this.ref as HTMLElement).focus()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
renderIcon() {
|
|
228
|
+
const {
|
|
229
|
+
display,
|
|
230
|
+
renderIcon,
|
|
231
|
+
variant: variantProp,
|
|
232
|
+
size: sizeProp
|
|
233
|
+
} = this.props
|
|
234
|
+
|
|
235
|
+
warn(
|
|
236
|
+
// if display prop is used, warn about icon or TruncateText
|
|
237
|
+
display === undefined,
|
|
238
|
+
'[Link] Using the display property with an icon may cause layout issues.'
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
// Determine the actual size being used (considering deprecated variants)
|
|
242
|
+
let size = sizeProp
|
|
243
|
+
if (variantProp === 'inline-small' || variantProp === 'standalone-small') {
|
|
244
|
+
size = sizeProp || 'small'
|
|
245
|
+
} else if (
|
|
246
|
+
(variantProp === 'inline' || variantProp === 'standalone') &&
|
|
247
|
+
!sizeProp
|
|
248
|
+
) {
|
|
249
|
+
size = 'medium'
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Map Link sizes to icon sizes
|
|
253
|
+
const linkSizeToIconSize = {
|
|
254
|
+
small: 'xs',
|
|
255
|
+
medium: 'sm',
|
|
256
|
+
large: 'lg'
|
|
257
|
+
} as const
|
|
258
|
+
|
|
259
|
+
const iconSize =
|
|
260
|
+
linkSizeToIconSize[(size || 'medium') as keyof typeof linkSizeToIconSize]
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<span css={this.props.styles?.icon}>
|
|
264
|
+
{renderIconWithProps(renderIcon, iconSize, undefined)}
|
|
265
|
+
</span>
|
|
266
|
+
)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
render() {
|
|
270
|
+
const {
|
|
271
|
+
children,
|
|
272
|
+
onClick,
|
|
273
|
+
onMouseEnter,
|
|
274
|
+
color,
|
|
275
|
+
href,
|
|
276
|
+
margin,
|
|
277
|
+
renderIcon,
|
|
278
|
+
iconPlacement,
|
|
279
|
+
...props
|
|
280
|
+
} = this.props
|
|
281
|
+
|
|
282
|
+
const { interaction } = this
|
|
283
|
+
|
|
284
|
+
const isDisabled = interaction === 'disabled'
|
|
285
|
+
|
|
286
|
+
const type =
|
|
287
|
+
this.element === 'button' || this.element === 'input'
|
|
288
|
+
? 'button'
|
|
289
|
+
: undefined
|
|
290
|
+
|
|
291
|
+
const tabIndex = this.role === 'button' && !isDisabled ? 0 : undefined
|
|
292
|
+
|
|
293
|
+
return (
|
|
294
|
+
<View
|
|
295
|
+
{...passthroughProps(props)}
|
|
296
|
+
elementRef={this.handleElementRef}
|
|
297
|
+
as={this.element}
|
|
298
|
+
display={this.display}
|
|
299
|
+
margin={margin}
|
|
300
|
+
href={href}
|
|
301
|
+
onMouseEnter={onMouseEnter}
|
|
302
|
+
onClick={this.handleClick}
|
|
303
|
+
onFocus={this.handleFocus}
|
|
304
|
+
onBlur={this.handleBlur}
|
|
305
|
+
aria-disabled={isDisabled ? 'true' : undefined}
|
|
306
|
+
role={this.role}
|
|
307
|
+
type={type}
|
|
308
|
+
tabIndex={tabIndex}
|
|
309
|
+
css={this.props.styles?.link}
|
|
310
|
+
data-cid={combineDataCid('Link', this.props)}
|
|
311
|
+
>
|
|
312
|
+
{renderIcon && iconPlacement === 'start' ? this.renderIcon() : null}
|
|
313
|
+
{children}
|
|
314
|
+
{renderIcon && iconPlacement === 'end' ? this.renderIcon() : null}
|
|
315
|
+
</View>
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export default Link
|
|
321
|
+
export { Link }
|