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

Remove @stacks/ui part 4 #4476

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
8 changes: 7 additions & 1 deletion src/app/common/hooks/account/use-account-gradient.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { useMemo } from 'react';

import { generateHash, hashValue, moduloRange, stringToHslColor } from '@stacks/ui-utils';
import chroma from 'chroma-js';

import {
generateHash,
hashValue,
moduloRange,
stringToHslColor,
} from '@app/common/utils/stacks-ui/ui/colors';

function generateGradientType(string: string) {
const gradientType = `${hashValue(string, ['linear', 'radial'])}-gradient`;
const isLinear = gradientType === 'linear-gradient';
Expand Down
2 changes: 1 addition & 1 deletion src/app/common/transactions/bitcoin/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { truncateMiddle } from '@stacks/ui-utils';
import { getAddressInfo } from 'bitcoin-address-validation';

import { BitcoinTransactionVectorOutput } from '@shared/models/transactions/bitcoin-transaction.model';
import { BitcoinTx } from '@shared/models/transactions/bitcoin-transaction.model';

import { sumNumbers } from '@app/common/math/helpers';
import { satToBtc } from '@app/common/money/unit-conversion';
import { truncateMiddle } from '@app/common/utils/stacks-ui/ui/truncateMiddle';

import { BtcSizeFeeEstimator } from './fees/btc-size-fee-estimator';

Expand Down
3 changes: 2 additions & 1 deletion src/app/common/transactions/stacks/transaction.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import {
addressHashModeToVersion,
addressToString,
} from '@stacks/transactions';
import { getContractName, truncateMiddle } from '@stacks/ui-utils';
import { BigNumber } from 'bignumber.js';

import { StacksTx, StacksTxStatus } from '@shared/models/transactions/stacks-transaction.model';

import { stacksValue } from '@app/common/stacks-utils';
import { getContractName } from '@app/common/utils/stacks-ui/ui/getContractName';
import { truncateMiddle } from '@app/common/utils/stacks-ui/ui/truncateMiddle';

export const statusFromTx = (tx: StacksTx): StacksTxStatus => {
const { tx_status } = tx;
Expand Down
12 changes: 12 additions & 0 deletions src/app/common/utils/stacks-ui/core/forwardRefWithAs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';

import { As, ForwardRefExoticComponentWithAs, ForwardRefWithAsRenderFunction } from './types';

export function forwardRefWithAs<Props, ComponentType extends As = 'div'>(
render: ForwardRefWithAsRenderFunction<Props, ComponentType>
) {
return React.forwardRef(render) as unknown as ForwardRefExoticComponentWithAs<
Props,
ComponentType
>;
}
112 changes: 112 additions & 0 deletions src/app/common/utils/stacks-ui/core/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import * as React from 'react';

type ElementTagNameMap = HTMLElementTagNameMap &
Pick<SVGElementTagNameMap, Exclude<keyof SVGElementTagNameMap, keyof HTMLElementTagNameMap>>;

type ElementByTag<TagName extends keyof ElementTagNameMap> = ElementTagNameMap[TagName] &
React.HTMLAttributes<ElementTagNameMap[TagName]>;

export type As<BaseProps = any> = React.ElementType<BaseProps>;

type PropsWithAs<ComponentProps, ComponentType extends As> = ComponentProps &
Omit<React.ComponentPropsWithRef<ComponentType>, 'as' | keyof ComponentProps> & {
as?: ComponentType;
};

type PropsFromAs<ComponentProps, ComponentType extends As> = (PropsWithAs<
ComponentProps,
ComponentType
> & { as: ComponentType }) &
PropsWithAs<ComponentProps, ComponentType>;

interface FunctionComponentWithAs<ComponentProps, ComponentType extends As> {
/**
* Inherited from React.FunctionComponent with modifications to support `as`
*/
<TT extends As>(
props: PropsWithAs<ComponentProps, TT>,
context?: any
): React.ReactElement<any, any> | null;
(
props: PropsWithAs<ComponentProps, ComponentType>,
context?: any
): React.ReactElement<any, any> | null;

/**
* Inherited from React.FunctionComponent
*/
displayName?: string;
propTypes?: React.WeakValidationMap<PropsWithAs<ComponentProps, ComponentType>>;
contextTypes?: React.ValidationMap<any>;
defaultProps?: Partial<PropsWithAs<ComponentProps, ComponentType>>;
}

interface ExoticComponentWithAs<ComponentProps, ComponentType extends As> {
/**
* **NOTE**: Exotic components are not callable.
* Inherited from React.ExoticComponent with modifications to support `as`
*/
<TT extends As>(props: PropsWithAs<ComponentProps, TT>): React.ReactElement | null;
(props: PropsWithAs<ComponentProps, ComponentType>): React.ReactElement | null;

/**
* Inherited from React.ExoticComponent
*/
readonly $$typeof: symbol;
}

interface NamedExoticComponentWithAs<ComponentProps, ComponentType extends As>
extends ExoticComponentWithAs<ComponentProps, ComponentType> {
/**
* Inherited from React.NamedExoticComponent
*/
displayName?: string;
}

export interface ForwardRefExoticComponentWithAs<ComponentProps, ComponentType extends As>
extends NamedExoticComponentWithAs<ComponentProps, ComponentType> {
/**
* Inherited from React.ForwardRefExoticComponent
* Will show `ForwardRef(${Component.displayName || Component.name})` in devtools by default,
* but can be given its own specific name
*/
defaultProps?: Partial<PropsWithAs<ComponentProps, ComponentType>>;
propTypes?: React.WeakValidationMap<PropsWithAs<ComponentProps, ComponentType>>;
}

export interface MemoExoticComponentWithAs<ComponentProps, ComponentType extends As>
extends NamedExoticComponentWithAs<ComponentProps, ComponentType> {
readonly type: ComponentType extends React.ComponentType
? ComponentType
: FunctionComponentWithAs<ComponentProps, ComponentType>;
}

export interface ForwardRefWithAsRenderFunction<ComponentProps, ComponentType extends As = 'div'> {
(
props: React.PropsWithRef<PropsFromAs<ComponentProps, ComponentType>>,
ref:
| ((
instance:
| (ComponentType extends keyof ElementTagNameMap ? ElementByTag<ComponentType> : any)
| null
) => void)
| React.MutableRefObject<
(ComponentType extends keyof ElementTagNameMap ? ElementByTag<ComponentType> : any) | null
>
| React.Ref<
(ComponentType extends keyof ElementTagNameMap ? ElementByTag<ComponentType> : any) | null
>
| any
): React.ReactElement | null;
displayName?: string;
// explicit rejected with `never` required due to
// https://github.com/microsoft/TypeScript/issues/36826
/**
* defaultProps are not supported on render functions
*/
defaultProps?: never;
/**
* propTypes are not supported on render functions
*/
propTypes?: never;
}
116 changes: 116 additions & 0 deletions src/app/common/utils/stacks-ui/ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Stacks UI Utils

Legacy utils taken from [Stacks UI](https://github.com/hirosystems/ui). Moved here initially but can be moved to monorepo

## Transactions

### getContractName

This will parse a string and return the contract name.

```ts
const contract =
'ST12EY99GS4YKP0CP2CFW6SEPWQ2CGVRWK5GHKDRV.market' ||
'ST12EY99GS4YKP0CP2CFW6SEPWQ2CGVRWK5GHKDRV.market::asset-name';

const name = getContractName(contract);

// market
```

### getAssetName

This will parse a fully qualified asset name string and pull out the name of the asset.

```ts
const contract = 'ST12EY99GS4YKP0CP2CFW6SEPWQ2CGVRWK5GHKDRV.market::asset-name';

const asset = getAssetName(contract);

// asset-name
```

### getAssetStringParts

This will parse a fully qualified asset name string and return the various parts: `address`, `contractName`, `assetName`.

```ts
const contract = 'ST12EY99GS4YKP0CP2CFW6SEPWQ2CGVRWK5GHKDRV.market::asset-name';

const { address, contractName, assetName } = getAssetStringParts(contract);

// ST12EY99GS4YKP0CP2CFW6SEPWQ2CGVRWK5GHKDRV
// market
// asset-name
```

## Strings

### truncateHex

This will truncate a hex, keeping the 0x out of the offset amount.

```ts
const hex = `0x33cc9a437e704e790958f7bb66492f5ad3a863ab3bcbef47138069725549a353`;

const shortened = truncateHex(hex, 4);
// 0x33cc...a353
```

### truncateMiddle

This will truncate any string in the middle, given an offset amount.

```ts
const hex = `0x33cc9a437e704e790958f7bb66492f5ad3a863ab3bcbef47138069725549a353`;

const shortened = truncateHex(hex, 4);
// 0x33cc...a353

const contract = 'ST12EY99GS4YKP0CP2CFW6SEPWQ2CGVRWK5GHKDRV.market';

const shortenedContract = truncateHex(contract, 4);
// ST12...KDRV.market
```

## Colors

### generateHash

This takes a string and generates a number has to use with `%`.

```ts
const hash = generateHash('some string');
// get a number between 0-360
const hue = hash % 360;
```

### hashValue

This function generates a hash from a string, and then gets a value from an array. An example usage would be to have an array of colors you'd like to pick from.

```ts
const colors = ['red', 'blue', 'green'];
const string = 'Hiro Protaganist';
const colorFromString = hashValue<('red' | 'blue' | 'green')[]>(string, colors);
// will be one of the colors
```

### stringToHslColor

This takes a string, saturation value, and lightness value to output a color in HSL.

```ts
const string = 'Hiro Protaganist';
const color = stringToHslColor(string, 60, 55);
// an hsl color
```

### moduloRange

This is a helper function to select a number from a range.

```ts
const restrictedHue = moduloRange(hash, [40, 60], true);
// will return a number between 40 and 60, including 60 as an option
```
75 changes: 75 additions & 0 deletions src/app/common/utils/stacks-ui/ui/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// NOTE: These functions only get used in useAccountGradient so could be relocated there
// we need to analyse the ColorsStringLiteral also and determine what we need from it

// Original ColorsStringLiteral below
export declare type ColorsStringLiteral =
| 'accent'
| 'brand'
| 'bg'
| 'bg-2'
| 'bg-3'
| 'bg-4'
| 'bg-alt'
| 'bg-light'
| 'invert'
| 'text-hover'
| 'text-title'
| 'text-caption'
| 'text-body'
| 'icon'
| 'input-placeholder'
| 'border'
| 'feedback-alert'
| 'feedback-error'
| 'feedback-success';

/**
* generateHash
* @param str - The string to hash
*/

export function generateHash(str: string): number {
let hash = 0;

for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}
return hash;
}

/**
* Get value from the provided `options` based on the hash of `str`.
*
* @param str - The string to hash
* @param options - array of options to get value from
*/

export function hashValue<T>(str: string, options: T[]): T {
let hash = generateHash(str);
hash = ((hash % options.length) + options.length) % options.length;
return options[hash];
}

/**
* stringToHslColor
*
* @param str - The string to hash
* @param saturation - saturation of result color (0 - 100)
* @param lightness - lightness of result color (0 - 100)
*/
export function stringToHslColor(str: string, saturation: number, lightness: number): string {
const hash = generateHash(str);
const hue = hash % 360;
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
}

export function moduloRange(x: number, range: [number, number], includeMax = false): number {
const max = range[1],
min = range[0],
d = max - min;
return x === max && includeMax ? x : ((((x - min) % d) + d) % d) + min;
}

// #4383 migrate / remove this
export const color = (name: ColorsStringLiteral): string => `var(--colors-${name})`;
30 changes: 30 additions & 0 deletions src/app/common/utils/stacks-ui/ui/dynamic-color-circle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ReactNode } from 'react';

import { BoxProps, Circle } from 'leather-styles/jsx';

// import { GridProps } from './grid';
import { useGradients } from './hooks/use-gradient';

interface DynamicColorCircleProps extends BoxProps {
string: string;
children?: ReactNode;
size: string | number;
}
// FIXME refactor this to be typed better
export function DynamicColorCircle({ string, children, ...rest }: DynamicColorCircleProps) {
const { getGradient } = useGradients();
const gradient = getGradient(string);

return (
<Circle
textTransform="capitalize"
flexShrink={0}
backgroundImage={gradient}
position="relative"
fontWeight="500"
{...rest}
>
{children}
</Circle>
);
}
Loading
Loading