-
Notifications
You must be signed in to change notification settings - Fork 403
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Migrate various utils from the Warp UI to the Widgets lib (#4856)
### Description More ground-work for the upcoming Warp Deploy app No new code, just migrating things from the Warp UI ### Backward compatibility Yes ### Testing Tested in Warp UI
- Loading branch information
Showing
19 changed files
with
265 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@hyperlane-xyz/utils': minor | ||
--- | ||
|
||
Add an isRelativeUrl function |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@hyperlane-xyz/sdk': minor | ||
--- | ||
|
||
Add a validateZodResult util function |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@hyperlane-xyz/widgets': minor | ||
--- | ||
|
||
Add various utility hooks: useIsSsr, useTimeout, useDebounce, useInterval |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,20 @@ | ||
import { z } from 'zod'; | ||
import { SafeParseReturnType, z } from 'zod'; | ||
|
||
import { rootLogger } from '@hyperlane-xyz/utils'; | ||
|
||
export function isCompliant<S extends Zod.Schema>(schema: S) { | ||
return (config: unknown): config is z.infer<S> => | ||
schema.safeParse(config).success; | ||
} | ||
|
||
export function validateZodResult<T>( | ||
result: SafeParseReturnType<T, T>, | ||
desc: string = 'config', | ||
): T { | ||
if (!result.success) { | ||
rootLogger.warn(`Invalid ${desc}`, result.error); | ||
throw new Error(`Invalid desc: ${result.error.toString()}`); | ||
} else { | ||
return result.data; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { expect } from 'chai'; | ||
|
||
import { isHttpsUrl, isRelativeUrl, isUrl } from './url.js'; | ||
|
||
describe('URL Utilities', () => { | ||
it('isUrl', () => { | ||
expect(isUrl(undefined)).to.be.false; | ||
expect(isUrl(null)).to.be.false; | ||
expect(isUrl('')).to.be.false; | ||
expect(isUrl('foobar')).to.be.false; | ||
expect(isUrl('https://hyperlane.xyz')).to.be.true; | ||
}); | ||
|
||
it('isHttpsUrl', () => { | ||
expect(isHttpsUrl(undefined)).to.be.false; | ||
expect(isHttpsUrl(null)).to.be.false; | ||
expect(isHttpsUrl('')).to.be.false; | ||
expect(isHttpsUrl('foobar')).to.be.false; | ||
expect(isHttpsUrl('http://hyperlane.xyz')).to.be.false; | ||
expect(isHttpsUrl('https://hyperlane.xyz')).to.be.true; | ||
}); | ||
|
||
it('isRelativeUrl', () => { | ||
expect(isRelativeUrl(undefined)).to.be.false; | ||
expect(isRelativeUrl(null)).to.be.false; | ||
expect(isRelativeUrl('')).to.be.false; | ||
expect(isRelativeUrl('foobar')).to.be.false; | ||
expect(isRelativeUrl('https://hyperlane.xyz')).to.be.false; | ||
expect(isRelativeUrl('/foobar')).to.be.true; | ||
expect(isRelativeUrl('/foo/bar', 'https://hyperlane.xyz')).to.be.true; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,29 @@ | ||
export function isUrl(value: string) { | ||
export function isUrl(value?: string | null) { | ||
try { | ||
if (!value) return false; | ||
const url = new URL(value); | ||
return !!url.hostname; | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
|
||
export function isHttpsUrl(value: string) { | ||
export function isHttpsUrl(value?: string | null) { | ||
try { | ||
if (!value) return false; | ||
const url = new URL(value); | ||
return url.protocol === 'https:'; | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
|
||
export function isRelativeUrl(value?: string | null, base?: string): boolean { | ||
try { | ||
if (!value || !value.startsWith('/')) return false; | ||
const url = new URL(value, base || 'https://hyperlane.xyz'); | ||
return !!url.pathname; | ||
} catch { | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React, { Component, PropsWithChildren, ReactNode } from 'react'; | ||
|
||
import { errorToString } from '@hyperlane-xyz/utils'; | ||
|
||
import { ErrorIcon } from '../icons/Error.js'; | ||
|
||
type Props = PropsWithChildren<{ | ||
supportLink?: ReactNode; | ||
}>; | ||
|
||
interface State { | ||
error: any; | ||
errorInfo: any; | ||
} | ||
|
||
export class ErrorBoundary extends Component<Props, State> { | ||
constructor(props: Props) { | ||
super(props); | ||
this.state = { error: null, errorInfo: null }; | ||
} | ||
|
||
componentDidCatch(error: any, errorInfo: any) { | ||
this.setState({ | ||
error, | ||
errorInfo, | ||
}); | ||
console.error('Error caught by error boundary', error, errorInfo); | ||
} | ||
|
||
render() { | ||
const errorInfo = this.state.error || this.state.errorInfo; | ||
if (errorInfo) { | ||
const details = errorToString(errorInfo, 1000); | ||
return ( | ||
<div className="htw-flex htw-h-screen htw-w-screen htw-items-center htw-justify-center htw-bg-gray-50"> | ||
<div className="htw-flex htw-flex-col htw-items-center htw-space-y-5"> | ||
<ErrorIcon width={80} height={80} /> | ||
<h1 className="htw-text-lg">Fatal Error Occurred</h1> | ||
<div className="htw-max-w-2xl htw-text-sm">{details}</div> | ||
{this.props.supportLink} | ||
</div> | ||
</div> | ||
); | ||
} | ||
return this.props.children; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React, { memo } from 'react'; | ||
|
||
import { ColorPalette } from '../color.js'; | ||
|
||
import { DefaultIconProps } from './types.js'; | ||
|
||
function _Error({ color, ...rest }: DefaultIconProps) { | ||
return ( | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" {...rest}> | ||
<path | ||
fill={color || ColorPalette.Black} | ||
d="M24 34q.7 0 1.18-.47.47-.48.47-1.18t-.47-1.18q-.48-.47-1.18-.47t-1.18.47q-.47.48-.47 1.18t.47 1.18Q23.3 34 24 34Zm.15-7.65q.65 0 1.07-.42.43-.43.43-1.08V15.2q0-.65-.42-1.07-.43-.43-1.08-.43-.65 0-1.07.42-.43.43-.43 1.08v9.65q0 .65.42 1.07.43.43 1.08.43ZM24 44q-4.1 0-7.75-1.57-3.65-1.58-6.38-4.3-2.72-2.73-4.3-6.38Q4 28.1 4 23.95q0-4.1 1.57-7.75 1.58-3.65 4.3-6.35 2.73-2.7 6.38-4.28Q19.9 4 24.05 4q4.1 0 7.75 1.57 3.65 1.58 6.35 4.28 2.7 2.7 4.28 6.35Q44 19.85 44 24q0 4.1-1.57 7.75-1.58 3.65-4.28 6.38t-6.35 4.3Q28.15 44 24 44Zm.05-3q7.05 0 12-4.97T41 23.95q0-7.05-4.95-12T24 7q-7.05 0-12.03 4.95Q7 16.9 7 24q0 7.05 4.97 12.03Q16.95 41 24.05 41ZM24 24Z" | ||
/> | ||
</svg> | ||
); | ||
} | ||
|
||
export const ErrorIcon = memo(_Error); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
import React from 'react'; | ||
|
||
import { ErrorBoundary } from '../components/ErrorBoundary'; | ||
|
||
function ErrorTest() { | ||
return ( | ||
<ErrorBoundary supportLink={<SupportLink />}> | ||
<ComponentThatThrows /> | ||
</ErrorBoundary> | ||
); | ||
} | ||
|
||
function ComponentThatThrows() { | ||
if (React) throw new Error('Something went wrong'); | ||
return <div>Hello</div>; | ||
} | ||
|
||
function SupportLink() { | ||
return <a>MyLink</a>; | ||
} | ||
|
||
const meta = { | ||
title: 'ErrorBoundary', | ||
component: ErrorTest, | ||
} satisfies Meta<typeof ErrorTest>; | ||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const DefaultErrorBoundary = { | ||
args: {}, | ||
} satisfies Story; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
// Based on https://usehooks.com/useDebounce | ||
export function useDebounce<T>(value: T, delayMs = 500): T { | ||
const [debouncedValue, setDebouncedValue] = useState<T>(value); | ||
|
||
useEffect(() => { | ||
const handler = setTimeout(() => { | ||
setDebouncedValue(value); | ||
}, delayMs); | ||
|
||
return () => { | ||
clearTimeout(handler); | ||
}; | ||
}, [value, delayMs]); | ||
|
||
return debouncedValue; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { useEffect, useState } from 'react'; | ||
|
||
export function useIsSsr() { | ||
const [isSsr, setIsSsr] = useState(true); | ||
// Effects are only run on the client side | ||
useEffect(() => { | ||
setIsSsr(false); | ||
}, []); | ||
return isSsr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react'; | ||
|
||
const useIsomorphicLayoutEffect = | ||
typeof window !== 'undefined' ? useLayoutEffect : useEffect; | ||
|
||
// https://usehooks-typescript.com/react-hook/use-interval | ||
export function useInterval(callback: () => void, delay: number | null) { | ||
const savedCallback = useRef(callback); | ||
|
||
// Remember the latest callback if it changes. | ||
useIsomorphicLayoutEffect(() => { | ||
savedCallback.current = callback; | ||
}, [callback]); | ||
|
||
// Set up the interval. | ||
useEffect(() => { | ||
// Don't schedule if no delay is specified. | ||
// Note: 0 is a valid value for delay. | ||
if (!delay && delay !== 0) { | ||
return; | ||
} | ||
|
||
const id = setInterval(() => savedCallback.current(), delay); | ||
|
||
return () => clearInterval(id); | ||
}, [delay]); | ||
} | ||
|
||
// https://medium.com/javascript-in-plain-english/usetimeout-react-hook-3cc58b94af1f | ||
export const useTimeout = ( | ||
callback: () => void, | ||
delay = 0, // in ms (default: immediately put into JS Event Queue) | ||
): (() => void) => { | ||
const timeoutIdRef = useRef<NodeJS.Timeout>(); | ||
|
||
const cancel = useCallback(() => { | ||
const timeoutId = timeoutIdRef.current; | ||
if (timeoutId) { | ||
timeoutIdRef.current = undefined; | ||
clearTimeout(timeoutId); | ||
} | ||
}, [timeoutIdRef]); | ||
|
||
useEffect(() => { | ||
if (delay >= 0) { | ||
timeoutIdRef.current = setTimeout(callback, delay); | ||
} | ||
return cancel; | ||
}, [callback, delay, cancel]); | ||
|
||
return cancel; | ||
}; |
Oops, something went wrong.