Skip to content

Commit 2f07d2e

Browse files
feat: ui.link (#980)
Closes #977 and Closes #860 **Need to clarify:** - Omitted implementation of `download`, `ping`, `href_lang`, `referrer_policy`, `router_options` since they do not appear to be working in the spectrum implementation, and they do not seem super needed (given that this is meant to serve as a basic link component) - If we want to implement said props, I can implement special logic for them --------- Co-authored-by: margaretkennedy <[email protected]>
1 parent 6ae6493 commit 2f07d2e

File tree

7 files changed

+327
-0
lines changed

7 files changed

+327
-0
lines changed

plugins/ui/docs/components/link.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Link
2+
3+
Links allow users to navigate to a specified location.
4+
5+
## Example
6+
7+
```python
8+
from deephaven import ui
9+
10+
my_link_basic = ui.link("Learn more about Deephaven", href="https://deephaven.io/")
11+
```
12+
13+
14+
## Content
15+
16+
The link component accepts other components, such as `text` and `icon`, as children.
17+
18+
```python
19+
from deephaven import ui
20+
21+
22+
@ui.component
23+
def ui_link_content_examples():
24+
return [
25+
ui.link(ui.icon("github"), href="https://github.com/deephaven"),
26+
ui.link("Deephaven Website", href="https://deephaven.io/"),
27+
]
28+
29+
30+
my_link_content_examples = ui_link_content_examples()
31+
```
32+
33+
34+
## Variants
35+
36+
Links can have different styles to indicate their purpose.
37+
38+
```python
39+
from deephaven import ui
40+
41+
42+
@ui.component
43+
def ui_link_variant_examples():
44+
return [
45+
ui.link("Deephaven", href="https://deephaven.io/", variant="primary"),
46+
ui.link(
47+
"Contact the team",
48+
href="https://deephaven.io/contact",
49+
variant="secondary",
50+
),
51+
]
52+
53+
54+
my_link_variant_examples = ui_link_variant_examples()
55+
```
56+
57+
## Over background
58+
59+
Links can be placed over a background to add a visual prominence to the link.
60+
61+
```python
62+
from deephaven import ui
63+
64+
65+
my_link_over_background_example = ui.view(
66+
ui.link(
67+
"Learn more about pandas here!",
68+
href="https://en.wikipedia.org/wiki/Giant_panda",
69+
variant="overBackground",
70+
),
71+
background_color="green-500",
72+
padding="size-300",
73+
)
74+
```
75+
76+
## Quiet State
77+
78+
The `is_quiet` prop makes the link "quiet". This can be useful when the link and its corresponding styling should not distract users from surrounding content.
79+
80+
```python
81+
from deephaven import ui
82+
83+
84+
my_link_is_quiet_example = ui.text(
85+
"You can ", ui.link("use quiet", is_quiet=True), " links inline."
86+
)
87+
```
88+
89+
90+
## API Reference
91+
92+
```{eval-rst}
93+
.. dhautofunction:: deephaven.ui.link
94+
```
95+

plugins/ui/docs/sidebar.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@
8989
"label": "image",
9090
"path": "components/image.md"
9191
},
92+
{
93+
"label": "link",
94+
"path": "components/link.md"
95+
},
9296
{
9397
"label": "picker",
9498
"path": "components/picker.md"

plugins/ui/src/deephaven/ui/components/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from .image import image
3030
from .item import item
3131
from .item_table_source import item_table_source
32+
from .link import link
3233
from .list_action_group import list_action_group
3334
from .list_action_menu import list_action_menu
3435
from .list_view import list_view
@@ -93,6 +94,7 @@
9394
"item_table_source",
9495
"illustrated_message",
9596
"image",
97+
"link",
9698
"list_view",
9799
"list_action_group",
98100
"list_action_menu",
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
from __future__ import annotations
2+
from typing import Any, Callable
3+
from .types import (
4+
Target,
5+
FocusEventCallable,
6+
KeyboardEventCallable,
7+
PressEventCallable,
8+
AlignSelf,
9+
CSSProperties,
10+
DimensionValue,
11+
JustifySelf,
12+
LayoutFlex,
13+
Position,
14+
)
15+
from .basic import component_element
16+
from ..elements import Element
17+
from ..types import LinkVariant
18+
19+
20+
def link(
21+
*children: Any,
22+
variant: LinkVariant | None = "primary",
23+
is_quiet: bool | None = None,
24+
auto_focus: bool | None = None,
25+
href: str | None = None,
26+
target: Target | None = None,
27+
rel: str | None = None,
28+
ping: str | None = None,
29+
download: str | None = None,
30+
href_lang: str | None = None,
31+
referrer_policy: str | None = None,
32+
on_press: PressEventCallable | None = None,
33+
on_press_start: PressEventCallable | None = None,
34+
on_press_end: PressEventCallable | None = None,
35+
on_press_up: PressEventCallable | None = None,
36+
on_press_change: Callable[[bool], None] | None = None,
37+
on_focus: FocusEventCallable | None = None,
38+
on_blur: FocusEventCallable | None = None,
39+
on_focus_change: Callable[[bool], None] | None = None,
40+
on_key_down: KeyboardEventCallable | None = None,
41+
on_key_up: KeyboardEventCallable | None = None,
42+
flex: LayoutFlex | None = None,
43+
flex_grow: float | None = None,
44+
flex_shrink: float | None = None,
45+
flex_basis: DimensionValue | None = None,
46+
align_self: AlignSelf | None = None,
47+
justify_self: JustifySelf | None = None,
48+
order: int | None = None,
49+
grid_area: str | None = None,
50+
grid_row: str | None = None,
51+
grid_column: str | None = None,
52+
grid_row_start: str | None = None,
53+
grid_row_end: str | None = None,
54+
grid_column_start: str | None = None,
55+
grid_column_end: str | None = None,
56+
margin: DimensionValue | None = None,
57+
margin_top: DimensionValue | None = None,
58+
margin_bottom: DimensionValue | None = None,
59+
margin_start: DimensionValue | None = None,
60+
margin_end: DimensionValue | None = None,
61+
margin_x: DimensionValue | None = None,
62+
margin_y: DimensionValue | None = None,
63+
width: DimensionValue | None = None,
64+
height: DimensionValue | None = None,
65+
min_width: DimensionValue | None = None,
66+
min_height: DimensionValue | None = None,
67+
max_width: DimensionValue | None = None,
68+
max_height: DimensionValue | None = None,
69+
position: Position | None = None,
70+
top: DimensionValue | None = None,
71+
bottom: DimensionValue | None = None,
72+
left: DimensionValue | None = None,
73+
right: DimensionValue | None = None,
74+
start: DimensionValue | None = None,
75+
end: DimensionValue | None = None,
76+
z_index: int | None = None,
77+
is_hidden: bool | None = None,
78+
aria_label: str | None = None,
79+
aria_labelledby: str | None = None,
80+
aria_describedby: str | None = None,
81+
aria_details: str | None = None,
82+
UNSAFE_class_name: str | None = None,
83+
UNSAFE_style: CSSProperties | None = None,
84+
) -> Element:
85+
"""
86+
A link is used for navigating between locations.
87+
88+
Args:
89+
*children: The content to display in the link.
90+
variant: The background color of the link.
91+
is_quiet: Whether the link should be displayed with a quiet style.
92+
auto_focus: Whether the element should receive focus on render.
93+
href: A URL to link to.
94+
target: The target window for the link.
95+
rel: The relationship between the linked resource and the current page.
96+
ping: A space-separated list of URLs to ping when the link is followed.
97+
download: Causes the browser to download the linked URL.
98+
href_lang: Hints at the human language of the linked URL.
99+
referrer_policy: How much of the referrer to send when following the link.
100+
on_press: Function called when the link is pressed.
101+
on_press_start: Function called when the link is pressed and held.
102+
on_press_end: Function called when the link is released after being pressed.
103+
on_press_up: Function called when the link is released.
104+
on_press_change: Function called when the pressed state changes.
105+
on_focus: Function called when the link receives focus.
106+
on_blur: Function called when the link loses focus.
107+
on_focus_change: Function called when the focus state changes.
108+
on_key_down: Function called when a key is pressed down.
109+
on_key_up: Function called when a key is released.
110+
flex: When used in a flex layout, specifies how the element will grow or shrink to fit the space available.
111+
flex_grow: When used in a flex layout, specifies how the element will grow to fit the space available.
112+
flex_shrink: When used in a flex layout, specifies how the element will shrink to fit the space available.
113+
flex_basis: When used in a flex layout, specifies the initial main size of the element.
114+
align_self: Overrides the alignItems property of a flex or grid container.
115+
justify_self: Species how the element is justified inside a flex or grid container.
116+
order: The layout order for the element within a flex or grid container.
117+
grid_area: When used in a grid layout specifies, specifies the named grid area that the element should be placed in within the grid.
118+
grid_row: When used in a grid layout, specifies the row the element should be placed in within the grid.
119+
grid_column: When used in a grid layout, specifies the column the element should be placed in within the grid.
120+
grid_row_start: When used in a grid layout, specifies the starting row to span within the grid.
121+
grid_row_end: When used in a grid layout, specifies the ending row to span within the grid.
122+
grid_column_start: When used in a grid layout, specifies the starting column to span within the grid.
123+
grid_column_end: When used in a grid layout, specifies the ending column to span within the grid.
124+
margin: The margin for all four sides of the element.
125+
margin_top: The margin for the top side of the element.
126+
margin_bottom: The margin for the bottom side of the element.
127+
margin_start: The margin for the logical start side of the element, depending on layout direction.
128+
margin_end: The margin for the logical end side of the element, depending on layout direction.
129+
margin_x: The margin for the left and right sides of the element.
130+
margin_y: The margin for the top and bottom sides of the element.
131+
width: The width of the element.
132+
height: The height of the element.
133+
min_width: The minimum width of the element.
134+
min_height: The minimum height of the element.
135+
max_width: The maximum width of the element.
136+
max_height: The maximum height of the element.
137+
position: Specifies how the element is position.
138+
top: The top position of the element.
139+
bottom: The bottom position of the element.
140+
left: The left position of the element.
141+
right: The right position of the element.
142+
start: The logical start position of the element, depending on layout direction.
143+
end: The logical end position of the element, depending on layout direction.
144+
z_index: The stacking order for the element
145+
is_hidden: Hides the element.
146+
aria_label: Defines a string value that labels the current element.
147+
aria_labelledby: Identifies the element (or elements) that labels the current element.
148+
aria_describedby: Identifies the element (or elements) that describes the object.
149+
aria_details: Identifies the element (or elements) that provide a detailed, extended description for the object.
150+
UNSAFE_class_name: Set the CSS className for the element. Only use as a last resort. Use style props instead.
151+
UNSAFE_style: Set the inline style for the element. Only use as a last resort. Use style props instead.
152+
153+
Returns:
154+
The rendered link element.
155+
156+
"""
157+
return component_element(
158+
"Link",
159+
*children,
160+
variant=variant,
161+
is_quiet=is_quiet,
162+
auto_focus=auto_focus,
163+
href=href,
164+
target=target,
165+
rel=rel,
166+
ping=ping,
167+
download=download,
168+
href_lang=href_lang,
169+
referrer_policy=referrer_policy,
170+
on_press=on_press,
171+
on_press_start=on_press_start,
172+
on_press_end=on_press_end,
173+
on_press_up=on_press_up,
174+
on_press_change=on_press_change,
175+
on_focus=on_focus,
176+
on_blur=on_blur,
177+
on_focus_change=on_focus_change,
178+
on_key_down=on_key_down,
179+
on_key_up=on_key_up,
180+
flex=flex,
181+
flex_grow=flex_grow,
182+
flex_shrink=flex_shrink,
183+
flex_basis=flex_basis,
184+
align_self=align_self,
185+
justify_self=justify_self,
186+
order=order,
187+
grid_area=grid_area,
188+
grid_row=grid_row,
189+
grid_column=grid_column,
190+
grid_row_start=grid_row_start,
191+
grid_row_end=grid_row_end,
192+
grid_column_start=grid_column_start,
193+
grid_column_end=grid_column_end,
194+
margin=margin,
195+
margin_top=margin_top,
196+
margin_bottom=margin_bottom,
197+
margin_start=margin_start,
198+
margin_end=margin_end,
199+
margin_x=margin_x,
200+
margin_y=margin_y,
201+
width=width,
202+
height=height,
203+
min_width=min_width,
204+
min_height=min_height,
205+
max_width=max_width,
206+
max_height=max_height,
207+
position=position,
208+
top=top,
209+
bottom=bottom,
210+
left=left,
211+
right=right,
212+
start=start,
213+
end=end,
214+
z_index=z_index,
215+
is_hidden=is_hidden,
216+
aria_label=aria_label,
217+
aria_labelledby=aria_labelledby,
218+
aria_describedby=aria_describedby,
219+
aria_details=aria_details,
220+
UNSAFE_class_name=UNSAFE_class_name,
221+
UNSAFE_style=UNSAFE_style,
222+
)

plugins/ui/src/deephaven/ui/types/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ class SliderChange(TypedDict):
506506
ListViewOverflowMode = Literal["truncate", "wrap"]
507507
ActionGroupDensity = Literal["compact", "regular"]
508508
TabDensity = Literal["compact", "regular"]
509+
LinkVariant = Literal["primary", "secondary", "over_background"]
509510
Dependencies = Union[Tuple[Any], List[Any]]
510511
Selection = Sequence[Key]
511512
LocalTime = DType

plugins/ui/src/js/src/elements/model/ElementConstants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export const ELEMENT_NAME = {
4949
item: uiComponentName('Item'),
5050
listActionGroup: uiComponentName('ListActionGroup'),
5151
listActionMenu: uiComponentName('ListActionMenu'),
52+
link: uiComponentName('Link'),
5253
listView: uiComponentName('ListView'),
5354
numberField: uiComponentName('NumberField'),
5455
picker: uiComponentName('Picker'),

plugins/ui/src/js/src/widget/WidgetUtils.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
DialogTrigger,
1414
Heading,
1515
Item,
16+
Link,
1617
ListActionGroup,
1718
ListActionMenu,
1819
NumberField,
@@ -130,6 +131,7 @@ export const elementComponentMap = {
130131
[ELEMENT_NAME.illustratedMessage]: IllustratedMessage,
131132
[ELEMENT_NAME.image]: Image,
132133
[ELEMENT_NAME.item]: Item,
134+
[ELEMENT_NAME.link]: Link,
133135
[ELEMENT_NAME.listActionGroup]: ListActionGroup,
134136
[ELEMENT_NAME.listActionMenu]: ListActionMenu,
135137
[ELEMENT_NAME.listView]: ListView,

0 commit comments

Comments
 (0)