Skip to content

Commit

Permalink
Import Storybook (#144)
Browse files Browse the repository at this point in the history
* feat: configure storybook

* feat: implement stories for EllipsisMiddle and AddressText
  • Loading branch information
WhiteMinds authored Nov 17, 2023
1 parent 39d4923 commit 10133fa
Show file tree
Hide file tree
Showing 11 changed files with 5,047 additions and 131 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
root: true,
extends: ['airbnb', 'plugin:prettier/recommended'],
extends: ['airbnb', 'plugin:prettier/recommended', 'plugin:storybook/recommended'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'react-hooks', 'unused-imports'],
globals: {
Expand Down
22 changes: 22 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { StorybookConfig } from '@storybook/react-webpack5'

const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/preset-create-react-app',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
'@storybook/addon-storysource',
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
docs: {
autodocs: true,
},
staticDirs: ['../public'],
}
export default config
23 changes: 23 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'antd/dist/antd.css'
// This should be after all third-party library styles so that it can override them.
import '../src/index.css'
import '../src/utils/i18n'
import type { Preview } from '@storybook/react'
import { MINIMAL_VIEWPORTS, INITIAL_VIEWPORTS } from '@storybook/addon-viewport'

const preview: Preview = {
parameters: {
viewport: {
viewports: { ...MINIMAL_VIEWPORTS, ...INITIAL_VIEWPORTS },
},
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
}

export default preview
23 changes: 20 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@sentry/react": "7.65.0",
"@sentry/tracing": "7.65.0",
"@spore-sdk/core": "^0.1.0-beta.10",
"@tanstack/react-query": "4.0.5",
"antd": "4.24.5",
"axios": "0.21.4",
"bignumber.js": "9.1.2",
Expand All @@ -28,7 +29,6 @@
"react-dom": "17.0.2",
"react-i18next": "11.18.6",
"react-outside-click-handler": "^1.3.0",
"@tanstack/react-query": "4.0.5",
"react-resize-detector": "7.1.2",
"react-router": "5.3.4",
"react-router-dom": "5.3.4",
Expand All @@ -38,6 +38,16 @@
},
"devDependencies": {
"@sentry/webpack-plugin": "2.7.1",
"@storybook/addon-essentials": "7.5.3",
"@storybook/addon-interactions": "7.5.3",
"@storybook/addon-links": "7.5.3",
"@storybook/addon-onboarding": "1.0.8",
"@storybook/addon-storysource": "^7.5.3",
"@storybook/blocks": "7.5.3",
"@storybook/preset-create-react-app": "7.5.3",
"@storybook/react": "7.5.3",
"@storybook/react-webpack5": "7.5.3",
"@storybook/testing-library": "0.2.2",
"@testing-library/react": "12.1.5",
"@types/echarts": "4.9.21",
"@types/eslint": "8.44.6",
Expand All @@ -52,6 +62,7 @@
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "6.9.1",
"antd-dayjs-webpack-plugin": "^1.0.6",
"babel-plugin-named-exports-order": "0.0.2",
"create-react-app": "^5.0.0",
"eslint": "8.52.0",
"eslint-config-airbnb": "18.2.1",
Expand All @@ -61,16 +72,19 @@
"eslint-plugin-prettier": "3.4.1",
"eslint-plugin-react": "7.31.11",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-storybook": "^0.6.15",
"eslint-plugin-unused-imports": "^3.0.0",
"husky": "^7.0.1",
"jest-styled-components": "^7.0.5",
"mockdate": "^2.0.5",
"postcss-scss": "4.0.8",
"postcss-styled-syntax": "^0.4.0",
"prettier": "^2.8.8",
"prop-types": "15.8.1",
"react-app-rewired": "2.2.1",
"react-test-renderer": "^17.0.2",
"rxjs": "7.8.1",
"storybook": "7.5.3",
"stylelint": "^15.10.1",
"stylelint-config-standard": "^34.0.0",
"stylelint-config-standard-scss": "^11.0.0",
Expand All @@ -79,15 +93,18 @@
"stylelint-processor-styled-components": "^1.10.0",
"timezone-mock": "^1.1.4",
"ts-jest": "27.1.5",
"typescript": "4.9.5"
"typescript": "4.9.5",
"webpack": "5.89.0"
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --watchAll=false",
"eject": "react-app-rewired eject",
"husky:init": "husky install",
"prepare": "husky install"
"prepare": "husky install",
"storybook": "storybook dev -p 3000",
"build-storybook": "storybook build"
},
"jest": {
"displayName": "Unit Test"
Expand Down
4 changes: 4 additions & 0 deletions src/components/AddressText/index.stories.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.border {
border: 1px solid #000;
box-sizing: content-box;
}
63 changes: 63 additions & 0 deletions src/components/AddressText/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { Meta, StoryObj } from '@storybook/react'

import AddressText from '.'
import styles from './index.stories.module.scss'
import { useForkedState } from '../../utils/hook'

const meta = {
component: AddressText,
argTypes: {
children: {
// In React 17, `FC<P>` is wrapped in `PropsWithChildren<P>`, causing the type of `children` to be unrecognizable by Storybook.
description: 'This item will be used as text when text is empty.',
type: 'string',
},
},
} satisfies Meta<typeof AddressText>

export default meta
type Story = StoryObj<typeof meta>

const addressHash = 'ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqflz4emgssc6nqj4yv3nfv2sca7g9dzhscgmg28x'

export const Primary: Story = {
parameters: {
viewport: {
defaultViewport: 'mobile2',
},
},
args: {
children: addressHash,
},
}

export const UseTextWidthForPlaceholderWidth: Story = {
parameters: {
viewport: {
defaultViewport: 'tablet',
},
},
args: {
children: addressHash,
useTextWidthForPlaceholderWidth: true,
className: styles.border,
},
render: function Render(args) {
const [useTextWidthForPlaceholderWidth, setUseTextWidthForPlaceholderWidth] = useForkedState(
args.useTextWidthForPlaceholderWidth,
)

return (
<div>
<AddressText {...args} useTextWidthForPlaceholderWidth={useTextWidthForPlaceholderWidth} />
<button
type="button"
onClick={() => setUseTextWidthForPlaceholderWidth(value => !value)}
style={{ marginTop: 16 }}
>
toggle useTextWidthForPlaceholderWidth
</button>
</div>
)
},
}
80 changes: 80 additions & 0 deletions src/components/EllipsisMiddle/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { Meta, StoryObj } from '@storybook/react'

import EllipsisMiddle from '.'
import { useForkedState } from '../../utils/hook'

const meta = {
component: EllipsisMiddle,
parameters: {
viewport: {
defaultViewport: 'tablet',
},
},
argTypes: {
children: {
// In React 17, `FC<P>` is wrapped in `PropsWithChildren<P>`, causing the type of `children` to be unrecognizable by Storybook.
description: 'This item will be used as text when text is empty.',
type: 'string',
},
},
} satisfies Meta<typeof EllipsisMiddle>

export default meta
type Story = StoryObj<typeof meta>

function getSentence(count: number) {
return new Array(count)
.fill(null)
.map((_, idx) => `This is a sentence ${idx}.`)
.join(' ')
}

export const ShortSentence: Story = {
args: {
children: getSentence(1),
},
}

export const LongSentence: Story = {
args: {
children: getSentence(10),
},
}

export const MinStartLen: Story = {
parameters: {
viewport: {
defaultViewport: 'mobile1',
},
},
args: {
minStartLen: 40,
children: getSentence(10),
},
}

export const UseTextWidthForPlaceholderWidth: Story = {
args: {
children: getSentence(1),
useTextWidthForPlaceholderWidth: true,
style: { border: '1px solid #000', boxSizing: 'content-box' },
},
render: function Render(args) {
const [useTextWidthForPlaceholderWidth, setUseTextWidthForPlaceholderWidth] = useForkedState(
args.useTextWidthForPlaceholderWidth,
)

return (
<div>
<EllipsisMiddle {...args} useTextWidthForPlaceholderWidth={useTextWidthForPlaceholderWidth} />
<button
type="button"
onClick={() => setUseTextWidthForPlaceholderWidth(value => !value)}
style={{ marginTop: 16 }}
>
toggle useTextWidthForPlaceholderWidth
</button>
</div>
)
},
}
4 changes: 3 additions & 1 deletion src/components/EllipsisMiddle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { createTextWidthMeasurer } from '../../utils/string'

const EllipsisMiddle: FC<
HTMLAttributes<HTMLDivElement> & {
/** This item will be used as text when text is empty. */
children?: string
/** When this item is not empty, ignore the value of `children`. */
text?: string
// Any key that represents the use of a different font
/** Any key that represents the use of a different font. */
fontKey?: string | number | boolean
minStartLen?: number
minEndLen?: number
Expand Down
10 changes: 8 additions & 2 deletions src/utils/hook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState, useRef, useMemo, useCallback, RefObject } from 'react'
import { useEffect, useState, useRef, useMemo, useCallback, RefObject, Dispatch, SetStateAction } from 'react'
import {
AddressPrefix,
addressToScript,
Expand All @@ -14,8 +14,8 @@ import { deprecatedAddrToNewAddr } from './util'
import { startEndEllipsis } from './string'
import { ListPageParams, PageParams, THEORETICAL_EPOCH_TIME, EPOCHS_PER_HALVING } from '../constants/common'
import { omit } from './object'
// TODO: This file depends on higher-level abstractions, so it should not be in the utils folder. It should be moved to `src/hooks/index.ts`.
import { useParseDate } from './date'
// TODO: This file depends on higher-level abstractions, so it should not be in the utils folder. It should be moved to `src/hooks/index.ts`.
import { useStatistics } from '../services/ExplorerService'
import { cacheService } from '../services/CacheService'

Expand All @@ -35,6 +35,12 @@ export function usePrevious<T>(value: T): T | undefined {
return ref.current
}

export function useForkedState<S>(basedState: S): [S, Dispatch<SetStateAction<S>>] {
const [state, setState] = useState<S>(basedState)
useEffect(() => setState(basedState), [basedState])
return [state, setState]
}

export const useInterval = (callback: () => void, delay: number, deps: any[] = []) => {
const savedCallback = useRef(() => {})
useEffect(() => {
Expand Down
1 change: 1 addition & 0 deletions src/utils/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import i18n from 'i18next'
import { initReactI18next, useTranslation } from 'react-i18next'
import en from '../locales/en.json'
import zh from '../locales/zh.json'
// TODO: This file depends on higher-level abstractions, so it should not be in the utils folder.
import { appSettings } from '../services/AppSettings'
import { includes } from './array'

Expand Down
Loading

1 comment on commit 10133fa

@vercel
Copy link

@vercel vercel bot commented on 10133fa Nov 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.