Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 6aca0e6

Browse files
authored
svelte: Update messaging and link indicators (#61038)
This commit removes the info banner and adds an experimental badge with popover instead. I'm sure the messaging in the popover can be improved. Maybe we'll give people a way to permanently opt-out. This also removes the styling for external links, which, toghether with the changes to the repo URL matching, means that the `data-sveltekit-reload` attributes are not necessary anymore. Because I made changes to the popover logic, namely making it possible to show and hide the popover on hover, I used that opportunity to migrate from the deprecated popperjs to floating-ui, which resolves some issues with the tooltip in hovercards. Eventually we should probably standardize on using melt-ui for popovers too (or whatever library we will use eventually) but for now I still find floating-ui to be easier to use than the corresponding melt-ui components.
1 parent 4bca034 commit 6aca0e6

17 files changed

+290
-304
lines changed

client/web-sveltekit/BUILD.bazel

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ SRCS = [
4545

4646
BUILD_DEPS = [
4747
":node_modules/@faker-js/faker",
48+
":node_modules/@floating-ui/dom",
4849
":node_modules/@graphql-codegen/cli",
49-
":node_modules/@graphql-codegen/typescript",
50-
":node_modules/@graphql-codegen/typescript-operations",
5150
":node_modules/@graphql-codegen/near-operation-file-preset",
5251
":node_modules/@graphql-codegen/typed-document-node",
52+
":node_modules/@graphql-codegen/typescript",
53+
":node_modules/@graphql-codegen/typescript-operations",
5354
":node_modules/@graphql-tools/utils",
5455
":node_modules/@melt-ui/svelte",
55-
":node_modules/@popperjs/core",
5656
":node_modules/@sourcegraph/branded",
5757
":node_modules/@sourcegraph/common",
5858
":node_modules/@sourcegraph/http-client",

client/web-sveltekit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@
6565
},
6666
"type": "module",
6767
"dependencies": {
68+
"@floating-ui/dom": "^1.6.3",
6869
"@melt-ui/svelte": "^0.76.0",
69-
"@popperjs/core": "^2.11.8",
7070
"@sourcegraph/branded": "workspace:*",
7171
"@sourcegraph/client-api": "workspace:*",
7272
"@sourcegraph/common": "workspace:*",

client/web-sveltekit/src/lib/Popover.svelte

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,94 @@
11
<script lang="ts">
2-
import type { Placement } from '@popperjs/core'
2+
import type { Placement } from '@floating-ui/dom'
33
4-
import { createPopover, onClickOutside } from './dom'
5-
import { afterUpdate } from 'svelte'
4+
import { popover, onClickOutside, portal } from './dom'
5+
import type { Action } from 'svelte/action'
66
77
export let placement: Placement = 'bottom'
8-
9-
const { update, popover } = createPopover()
8+
/**
9+
* Show the popover when hovering over the trigger.
10+
*/
11+
export let showOnHover = false
1012
1113
let isOpen = false
1214
let trigger: HTMLElement | null
15+
let popoverContainer: HTMLElement | null
1316
1417
function toggle(open?: boolean): void {
1518
isOpen = open === undefined ? !isOpen : open
1619
}
1720
18-
function clickOutside(event: { detail: HTMLElement }): void {
21+
function handleClickOutside(event: { detail: HTMLElement }): void {
1922
if (event.detail !== trigger && !trigger?.contains(event.detail)) {
2023
isOpen = false
2124
}
2225
}
2326
24-
function registerTrigger(node: HTMLElement) {
27+
const registerTrigger: Action<HTMLElement> = node => {
2528
trigger = node
29+
30+
function handleMouseEnterTrigger(): void {
31+
isOpen = true
32+
}
33+
34+
function handleMouseLeaveTrigger(event: MouseEvent): void {
35+
// It should be possible to move the mouse from the trigger to the popover without closing it
36+
if (event.relatedTarget && !popoverContainer?.contains(event.relatedTarget as Node)) {
37+
isOpen = false
38+
}
39+
}
40+
41+
if (showOnHover) {
42+
node.addEventListener('mouseenter', handleMouseEnterTrigger)
43+
node.addEventListener('mouseleave', handleMouseLeaveTrigger)
44+
}
45+
46+
return {
47+
destroy() {
48+
trigger = null
49+
node.removeEventListener('mouseenter', handleMouseEnterTrigger)
50+
node.removeEventListener('mouseleave', handleMouseLeaveTrigger)
51+
},
52+
}
2653
}
2754
28-
afterUpdate(update)
55+
const registerPopoverContainer: Action<HTMLElement> = node => {
56+
popoverContainer = node
57+
function handleMouseLeavePopover(event: MouseEvent): void {
58+
// It should be possible to move the mouse from the popover to the trigger without closing it
59+
if (event.relatedTarget && !trigger?.contains(event.relatedTarget as Node)) {
60+
toggle(false)
61+
}
62+
}
63+
if (showOnHover) {
64+
node.addEventListener('mouseleave', handleMouseLeavePopover)
65+
}
66+
return {
67+
destroy() {
68+
popoverContainer = null
69+
node.removeEventListener('mouseleave', handleMouseLeavePopover)
70+
},
71+
}
72+
}
2973
</script>
3074

3175
<slot {toggle} {registerTrigger} />
3276
{#if trigger && isOpen}
33-
<div use:popover={{ target: trigger, options: { placement } }} use:onClickOutside on:click-outside={clickOutside}>
77+
<div
78+
use:registerPopoverContainer
79+
use:portal
80+
use:popover={{ reference: trigger, options: { placement, shift: { padding: 4 } } }}
81+
use:onClickOutside
82+
on:click-outside={handleClickOutside}
83+
>
3484
<slot name="content" {toggle} />
3585
</div>
3686
{/if}
3787

3888
<style lang="scss">
3989
div {
90+
position: absolute;
4091
isolation: isolate;
41-
z-index: 1000;
4292
min-width: 10rem;
4393
font-size: 0.875rem;
4494
background-clip: padding-box;

client/web-sveltekit/src/lib/Tooltip.stories.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
</script>
99

1010
<script lang="ts">
11-
const placements: Placement[] = ['auto', 'top', 'left', 'bottom', 'right']
11+
const placements: Placement[] = ['top', 'left', 'bottom', 'right']
1212
let count = 0
1313
</script>
1414

1515
<Story name="Default">
1616
<h2>Static Tooltip</h2>
1717
<p>
18-
<Tooltip tooltip="Some static tooltip text" placement="auto">
18+
<Tooltip tooltip="Some static tooltip text">
1919
<span>Hover over me</span>
2020
</Tooltip>
2121
</p>
Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
<script lang="ts" context="module">
2-
import type { Placement } from '@popperjs/core'
3-
import { placements } from '@popperjs/core'
2+
import type { Placement } from '@floating-ui/dom'
43
54
export type { Placement }
6-
export { placements }
75
</script>
86

97
<script lang="ts">
10-
import { createPopover, uniqueID } from './dom'
11-
import { afterUpdate } from 'svelte'
8+
import { popover, portal, uniqueID } from './dom'
129
1310
/**
1411
* The content of the tooltip.
@@ -25,14 +22,11 @@
2522
export let alwaysVisible = false
2623
2724
const id = uniqueID('tooltip')
28-
const { update, popover } = createPopover()
2925
3026
let visible = false
3127
let wrapper: HTMLElement
3228
let target: Element | null
3329
34-
afterUpdate(update)
35-
3630
function show() {
3731
visible = true
3832
}
@@ -43,14 +37,10 @@
4337
4438
$: options = {
4539
placement,
46-
modifiers: [
47-
{
48-
name: 'offset',
49-
options: {
50-
offset: [0, 8],
51-
},
52-
},
53-
],
40+
offset: 8,
41+
shift: {
42+
padding: 4,
43+
},
5444
}
5545
$: target = wrapper?.firstElementChild
5646
$: if (target && tooltip) {
@@ -68,9 +58,9 @@
6858
<slot />
6959
</div>
7060
{#if (alwaysVisible || visible) && target && tooltip}
71-
<div role="tooltip" {id} use:popover={{ target, options }}>
72-
{tooltip}
73-
<div data-popper-arrow />
61+
<div role="tooltip" {id} use:popover={{ reference: target, options }} use:portal>
62+
<div class="content">{tooltip}</div>
63+
<div data-arrow />
7464
</div>
7565
{/if}
7666

@@ -89,56 +79,53 @@
8979
--tooltip-padding-x: 0.5rem;
9080
--tooltip-margin: 0;
9181
82+
--tooltip-arrow-side: 8px solid transparent;
83+
--tooltip-arrow-main: 8px solid var(--tooltip-bg);
84+
9285
all: initial;
86+
position: absolute;
9387
isolation: isolate;
9488
font-family: inherit;
9589
font-size: var(--tooltip-font-size);
9690
font-style: normal;
9791
font-weight: normal;
9892
line-height: var(--tooltip-line-height);
9993
max-width: var(--tooltip-max-width);
100-
background-color: var(--tooltip-bg);
101-
border-radius: var(--tooltip-border-radius);
10294
color: var(--tooltip-color);
103-
padding: var(--tooltip-padding-y) var(--tooltip-padding-x);
10495
user-select: text;
10596
word-wrap: break-word;
10697
border: none;
10798
min-width: 0;
108-
z-index: 100;
109-
}
99+
width: max-content;
110100
111-
:global([data-popper-placement^='top']) > [data-popper-arrow] {
112-
bottom: -4px;
113-
}
101+
.content {
102+
background-color: var(--tooltip-bg);
103+
padding: var(--tooltip-padding-y) var(--tooltip-padding-x);
104+
border-radius: var(--tooltip-border-radius);
105+
}
114106
115-
:global([data-popper-placement^='bottom']) > [data-popper-arrow] {
116-
top: -4px;
117-
}
107+
:global([data-arrow][data-placement^='top']) {
108+
bottom: -4px;
109+
}
118110
119-
:global([data-popper-placement^='left']) > [data-popper-arrow] {
120-
right: -4px;
121-
}
111+
:global([data-arrow][data-placement^='bottom']) {
112+
top: -4px;
113+
}
114+
115+
:global([data-arrow][data-placement^='left']) {
116+
right: -4px;
117+
}
122118
123-
:global([data-popper-placement^='right']) > [data-popper-arrow] {
124-
left: -4px;
119+
:global([data-arrow][data-placement^='right']) {
120+
left: -4px;
121+
}
125122
}
126123
127-
[data-popper-arrow],
128-
[data-popper-arrow]::before {
124+
[data-arrow] {
129125
position: absolute;
130126
width: 8px;
131127
height: 8px;
132-
background: inherit;
133-
}
134-
135-
[data-popper-arrow] {
136-
visibility: hidden;
137-
138-
&::before {
139-
visibility: visible;
140-
content: '';
141-
transform: rotate(45deg);
142-
}
128+
transform: rotate(45deg);
129+
background-color: var(--tooltip-bg);
143130
}
144131
</style>

0 commit comments

Comments
 (0)