Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: render tooltip in root #2210

Merged
merged 7 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/pr_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ jobs:

code_style:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
strategy:
matrix:
style-command:
Expand Down
12 changes: 6 additions & 6 deletions apps/gallery/stories/composites/wui-tooltip-select.stories.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { Meta } from '@storybook/web-components'
import '@web3modal/ui/src/composites/wui-tooltip-select'
import type { WuiTooltipSelect } from '@web3modal/ui/src/composites/wui-tooltip-select'
import '@web3modal/ui/src/composites/wui-wallet-feature-button'
import type { WuiWalletFeatureButton } from '@web3modal/ui/src/composites/wui-wallet-feature-button'
import { html } from 'lit'
import '../../components/gallery-container'
import { iconOptions } from '../../utils/PresetUtils'

type Component = Meta<WuiTooltipSelect>
type Component = Meta<WuiWalletFeatureButton>

export default {
title: 'Composites/wui-tooltip-select',
title: 'Composites/wui-wallet-feature-button',
args: {
icon: 'card',
text: 'Buy'
Expand All @@ -23,8 +23,8 @@ export default {

export const Default: Component = {
render: args => html`
<gallery-container width="120"
><wui-tooltip-select icon=${args.icon} text=${args.text}></wui-tooltip-select>
<gallery-container width="120">
<wui-wallet-feature-button icon=${args.icon} text=${args.text}></wui-wallet-feature-button>
</gallery-container>
`
}
27 changes: 21 additions & 6 deletions dangerfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const PACKAGE_VERSION = ConstantsUtil.VERSION
const RELATIVE_IMPORT_SAME_DIR = `'./`
const RELATIVE_IMPORT_PARENT_DIR = `'../`
const RELATIVE_IMPORT_EXTENSION = `.js'`
const PRIVATE_FUNCTION_REGEX = /private\s+(\w+)\s*\(\s*\)/g

// -- Data --------------------------------------------------------------------
const { modified_files, created_files, deleted_files, diffForFile } = danger.git
Expand Down Expand Up @@ -50,7 +51,9 @@ checkPackageJsons()
async function checkUiPackage() {
const created_ui_components = created_files.filter(f => f.includes('ui/src/components'))
const created_ui_composites = created_files.filter(f => f.includes('ui/src/composites'))
const deleted_ui_composites = deleted_files.filter(f => f.includes('ui/src/composites'))
const created_ui_layout = created_files.filter(f => f.includes('ui/src/layout'))
const deleted_ui_layout = deleted_files.filter(f => f.includes('ui/src/layout'))
const created_ui_files = [
...created_ui_components,
...created_ui_composites,
Expand Down Expand Up @@ -82,7 +85,9 @@ async function checkUiPackage() {
fail(`${f} is missing \`${STATE_PROPERTIES_COMMENT}\` comment`)
}

if (diff?.added.includes('private ') && !diff.added.includes(PRIVATE_COMMENT)) {
const privateFunctionsAdded = diff?.added.match(PRIVATE_FUNCTION_REGEX)?.length

if (privateFunctionsAdded && !diff?.added.includes(PRIVATE_COMMENT)) {
message(
`${f} is missing \`${PRIVATE_COMMENT}\` comment, but seems to have private members. Check if this is correct`
)
Expand Down Expand Up @@ -119,13 +124,21 @@ async function checkUiPackage() {
const jsx_index_diff = jsx_index ? await diffForFile(jsx_index) : undefined
const created_ui_components_index_ts = created_ui_components.filter(f => f.endsWith('index.ts'))
const created_ui_composites_index_ts = created_ui_composites.filter(f => f.endsWith('index.ts'))
const deleted_ui_composites_index_ts = deleted_ui_composites.filter(f => f.endsWith('index.ts'))
const is_new_composites_added =
created_ui_composites_index_ts.length > deleted_ui_composites_index_ts.length
const created_ui_layout_index_ts = created_ui_layout.filter(f => f.endsWith('index.ts'))
const deleted_ui_layout_index_ts = deleted_ui_layout.filter(f => f.endsWith('index.ts'))
const is_new_layout_added = created_ui_layout_index_ts.length > deleted_ui_layout_index_ts.length

if (created_ui_components_index_ts.length && !ui_index_diff?.added.includes('src/components')) {
fail('New components were added, but not exported in ui/index.ts')
}

if (created_ui_composites_index_ts.length && !ui_index_diff?.added.includes('src/composites')) {
if (created_ui_composites_index_ts.length !== deleted_ui_composites_index_ts.length) {
fail('Number of created composites does not match number of deleted composites')
}
if (is_new_composites_added && !ui_index_diff?.added.includes('src/composites')) {
fail('New composites were added, but not exported in ui/index.ts')
}

Expand All @@ -141,19 +154,19 @@ async function checkUiPackage() {
)
}

if (created_ui_composites_index_ts.length && !jsx_index_diff?.added.includes('../composites')) {
if (is_new_composites_added && !jsx_index_diff?.added.includes('../composites')) {
fail('New composites were added, but not exported in ui/utils/JSXTypeUtil.ts')
}

if (created_ui_layout_index_ts.length && !jsx_index_diff?.added.includes('../layout')) {
if (is_new_layout_added && !jsx_index_diff?.added.includes('../layout')) {
fail('New layout components were added, but not exported in ui/utils/JSXTypeUtil.ts')
}

if (created_ui_components.length && !created_ui_components_stories.length) {
fail('New components were added, but no stories were created')
}

if (created_ui_composites.length && !created_ui_composites_stories.length) {
if (is_new_composites_added && !created_ui_composites_stories.length) {
fail('New composites were added, but no stories were created')
}

Expand Down Expand Up @@ -242,7 +255,9 @@ async function checkScaffoldHtmlPackage() {
fail(`${f} is missing \`${STATE_PROPERTIES_COMMENT}\` comment`)
}

if (diff?.added.includes('private ') && !diff.added.includes(PRIVATE_COMMENT)) {
const privateFunctionsAdded = diff?.added.match(PRIVATE_FUNCTION_REGEX)?.length

if (privateFunctionsAdded && !diff?.added.includes(PRIVATE_COMMENT)) {
message(
`${f} is missing \`${PRIVATE_COMMENT}\` comment, but seems to have private members. Check if this is correct`
)
Expand Down
3 changes: 3 additions & 0 deletions packages/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export type { SwapControllerState, SwapInputTarget } from './src/controllers/Swa
export { SendController } from './src/controllers/SendController.js'
export type { SendControllerState } from './src/controllers/SendController.js'

export { TooltipController } from './src/controllers/TooltipController.js'
export type { TooltipControllerState } from './src/controllers/TooltipController.js'

// -- Utils -------------------------------------------------------------------
export { AssetUtil } from './src/utils/AssetUtil.js'
export { ConstantsUtil } from './src/utils/ConstantsUtil.js'
Expand Down
71 changes: 71 additions & 0 deletions packages/core/src/controllers/TooltipController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { subscribeKey as subKey } from 'valtio/vanilla/utils'
import { proxy, subscribe as sub } from 'valtio/vanilla'

// -- Types --------------------------------------------- //
type TriggerRect = {
width: number
height: number
top: number
left: number
}

export interface TooltipControllerState {
message: string
triggerRect: TriggerRect
open: boolean
variant: 'shade' | 'fill'
}

type StateKey = keyof TooltipControllerState

// -- State --------------------------------------------- //
const state = proxy<TooltipControllerState>({
message: '',
open: false,
triggerRect: {
width: 0,
height: 0,
top: 0,
left: 0
},
variant: 'shade'
})

// -- Controller ---------------------------------------- //
export const TooltipController = {
state,

subscribe(callback: (newState: TooltipControllerState) => void) {
return sub(state, () => callback(state))
},

subscribeKey<K extends StateKey>(key: K, callback: (value: TooltipControllerState[K]) => void) {
return subKey(state, key, callback)
},

showTooltip({
message,
triggerRect,
variant
}: {
message: string
triggerRect: TriggerRect
variant: 'shade' | 'fill'
}) {
state.open = true
state.message = message
state.triggerRect = triggerRect
state.variant = variant
},

hide() {
state.open = false
state.message = ''
state.triggerRect = {
width: 0,
height: 0,
top: 0,
left: 0
}
}
}
44 changes: 44 additions & 0 deletions packages/core/tests/controllers/TooltipController.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest'
import { TooltipController } from '../../index.js'

// -- Constants ----------------------------------------------------------------
const mockTriggerRect = {
width: 100,
height: 100,
top: 100,
left: 100
}

const mockTooltip = {
message: 'Hello, World!',
triggerRect: mockTriggerRect,
variant: 'shade' as 'shade' | 'fill'
}

// -- Tests --------------------------------------------------------------------
describe('TooltipController', () => {
it('should have valid default state', () => {
expect(TooltipController.state).toEqual({
message: '',
open: false,
triggerRect: {
width: 0,
height: 0,
top: 0,
left: 0
},
variant: 'shade'
})
})

it('should show the tooltip as expected', () => {
TooltipController.showTooltip(mockTooltip)
expect(TooltipController.state.open).toEqual(true)
expect(TooltipController.state.message).toEqual('Hello, World!')
})

it('should hide the tooltip as expected', () => {
TooltipController.hide()
expect(TooltipController.state.open).toEqual(false)
})
})
2 changes: 2 additions & 0 deletions packages/scaffold/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export * from './src/partials/w3m-activity-list/index.js'
export * from './src/partials/w3m-input-token/index.js'
export * from './src/partials/w3m-input-address/index.js'
export * from './src/partials/w3m-wallet-send-details/index.js'
export * from './src/partials/w3m-tooltip/index.js'
export * from './src/partials/w3m-tooltip-trigger/index.js'

export { Web3ModalScaffold } from './src/client.js'
export type { LibraryOptions, ScaffoldOptions } from './src/client.js'
Expand Down
1 change: 1 addition & 0 deletions packages/scaffold/src/modal/w3m-modal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export class W3mModal extends LitElement {
<w3m-snackbar></w3m-snackbar>
</wui-card>
</wui-flex>
<w3m-tooltip></w3m-tooltip>
`
: null
}
Expand Down
2 changes: 1 addition & 1 deletion packages/scaffold/src/modal/w3m-modal/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default css`
}

wui-card {
max-width: 360px;
max-width: var(--w3m-modal-width);
width: 100%;
position: relative;
animation-duration: 0.2s;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,25 @@ export class W3mAccountWalletFeaturesWidget extends LitElement {
></wui-profile-button>
${this.tokenBalanceTemplate()}
<wui-flex gap="s">
<wui-tooltip-select
@click=${this.onBuyClick.bind(this)}
text="Buy"
icon="card"
></wui-tooltip-select>
<wui-tooltip-select
@click=${this.onSwapClick.bind(this)}
text="Swap"
icon="recycleHorizontal"
></wui-tooltip-select>
<wui-tooltip-select
@click=${this.onReceiveClick.bind(this)}
text="Receive"
icon="arrowBottomCircle"
></wui-tooltip-select>
<wui-tooltip-select
@click=${this.onSendClick.bind(this)}
text="Send"
icon="send"
></wui-tooltip-select>
<w3m-tooltip-trigger text="Buy">
<wui-wallet-feature-button @click=${this.onBuyClick.bind(this)} icon="card">
</wui-wallet-feature-button>
</w3m-tooltip-trigger>
<w3m-tooltip-trigger text="Swap">
<wui-wallet-feature-button @click=${this.onSwapClick.bind(this)} icon="recycleHorizontal">
</wui-wallet-feature-button>
</w3m-tooltip-trigger>
<w3m-tooltip-trigger text="Receive">
<wui-wallet-feature-button
@click=${this.onReceiveClick.bind(this)}
icon="arrowBottomCircle"
>
</wui-wallet-feature-button>
</w3m-tooltip-trigger>
<w3m-tooltip-trigger text="Send">
<wui-wallet-feature-button @click=${this.onSendClick.bind(this)} icon="send">
</wui-wallet-feature-button>
</w3m-tooltip-trigger>
</wui-flex>

<wui-tabs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ export default css`
margin-top: var(--wui-spacing-2l);
}

wui-tooltip-select {
width: 100%;
}

wui-tabs {
width: 100%;
}
Expand Down
56 changes: 56 additions & 0 deletions packages/scaffold/src/partials/w3m-tooltip-trigger/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { html, LitElement } from 'lit'
import { property } from 'lit/decorators.js'
import { customElement } from '@web3modal/ui'
import styles from './styles.js'
import { TooltipController } from '@web3modal/core'

@customElement('w3m-tooltip-trigger')
export class WuiTooltipTrigger extends LitElement {
public static override styles = [styles]

// -- State & Properties -------------------------------- //
@property() text = ''

// -- Render -------------------------------------------- //
public override render() {
return html`
<div
@pointermove=${this.onMouseEnter.bind(this)}
@pointerleave=${this.onMouseLeave.bind(this)}
>
${this.renderChildren()}
</div>
`
}

private renderChildren() {
return html`<slot></slot> `
}

// -- Private ------------------------------------------- //
private onMouseEnter() {
const rect = this.getBoundingClientRect()
TooltipController.showTooltip({
message: this.text,
triggerRect: {
width: rect.width,
height: rect.height,
left: rect.left,
top: rect.top
},
variant: 'shade'
})
}

private onMouseLeave(event: MouseEvent) {
if (!this.contains(event.relatedTarget as Node)) {
TooltipController.hide()
}
}
}

declare global {
interface HTMLElementTagNameMap {
'w3m-tooltip-trigger': WuiTooltipTrigger
}
}
Loading
Loading