Skip to content

Commit

Permalink
Apply react-docgen-typescript-plugin to generate storybook documentat…
Browse files Browse the repository at this point in the history
…ions from JSDoc (#931)

* chore(bezier-react): install @channel-io/react-docgen-typescript-plugin

* chore(@channel.io/bezier-react): apply react-docgen-typescript-plugin to production storybook

* chore(bezier-react): hide key, children, ref prop from documentation, expand enum values

* docs(bezier-react): add jsdoc to common component interfaces

* docs(bezier-react): add ArgsTable documentation to Avatar components

* docs(bezier-react): add ArgsTable documentation for Banner component

* docs(bezier-react): add ArgsTable documentation for Button component

* docs(bezier-react): add ArgsTable documentation for ButtonGroup component

* docs(bezier-react): add ArgsTable documentation to Icon component

* docs(bezier-react): add ArgsTable documentation for Stack components

* docs(bezier-react): add ArgsTable documentation to Tag, Badge components

* fix(bezier-react): use package from @channel.io scope

this package is public to anonymous user
  • Loading branch information
inhibitor1217 authored Nov 24, 2022
1 parent 1afab06 commit 34ccd70
Show file tree
Hide file tree
Showing 67 changed files with 343 additions and 508 deletions.
5 changes: 5 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-3.2.1.cjs

npmScopes:
channel-io:
npmPublishRegistry: "https://npm.pkg.github.com/"
npmRegistryServer: "https://npm.pkg.github.com/"
26 changes: 25 additions & 1 deletion packages/bezier-react/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const path = require('path')
const ReactDocgenTypescriptPlugin = require('@channel.io/react-docgen-typescript-plugin').default
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')

module.exports = {
Expand All @@ -20,6 +20,17 @@ module.exports = {
features: {
postcss: false,
},
typescript: {
/**
* @note
*
* default `typescript.reactDocgen` option is to use `react-docgen-typescript-plugin`,
* which is not compatible with TS <= 4.3
*
* so we need to disable and override it with our own plugin (@channel-io/react-docgen-typescript-plugin).
*/
reactDocgen: false,
},
webpackFinal: async (config) => {
// Apply tsconfig alias path
config.resolve.plugins = [
Expand All @@ -37,6 +48,19 @@ module.exports = {

config.resolve.extensions.push('.ts', '.tsx')

if (process.env.NODE_ENV === 'production') {
/**
* @note
*
* `react-docgen-typescript-plugin` introduces significant overhead
* when HMR is enabled, so we enable it only in production.
*/
config.plugins.push(new ReactDocgenTypescriptPlugin({
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
}))
}

return config
}
}
1 change: 1 addition & 0 deletions packages/bezier-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@babel/preset-env": "^7.14.2",
"@babel/preset-react": "^7.12.10",
"@babel/preset-typescript": "^7.12.7",
"@channel.io/react-docgen-typescript-plugin": "^1.0.0",
"@mdx-js/react": "^1.6.22",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^19.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Story, Meta } from '@storybook/react'
import { styled } from 'Foundation'
import { getTitle } from 'Utils/storyUtils'
import { StatusType } from 'Components/Status'
import Avatar from './Avatar'
import { Avatar } from './Avatar'
import AvatarProps, { AvatarSize } from './Avatar.types'

const MOCK_AVATAR_URL = 'https://cf.channel.io/thumb/200x200/pub-file/1/606d87d059a6093594c0/ch-symbol-filled-smiley-bg.png'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { render } from 'Utils/testUtils'
import DisabledOpacity from 'Constants/DisabledOpacity'
import { StatusType } from 'Components/Status'
import { AVATAR_BORDER_RADIUS_PERCENTAGE } from 'Components/Avatars/AvatarStyle'
import Avatar, { AVATAR_TEST_ID, AVATAR_WRAPPER_TEST_ID, STATUS_WRAPPER_TEST_ID } from './Avatar'
import { Avatar, AVATAR_TEST_ID, AVATAR_WRAPPER_TEST_ID, STATUS_WRAPPER_TEST_ID } from './Avatar'
import AvatarProps, { AvatarSize } from './Avatar.types'

jest.mock('Worklets/EnableCSSHoudini', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const AVATAR_WRAPPER_TEST_ID = 'bezier-react-avatar-wrapper'
export const AVATAR_TEST_ID = 'bezier-react-avatar'
export const STATUS_WRAPPER_TEST_ID = 'bezier-react-status-wrapper'

function Avatar({
export const Avatar = forwardRef(function Avatar({
avatarUrl = '',
fallbackUrl = defaultAvatarUrl,
size = AvatarSize.Size24,
Expand Down Expand Up @@ -102,6 +102,4 @@ forwardedRef: React.Ref<HTMLDivElement>,
</AvatarImageWrapper>
</AvatarWrapper>
)
}

export default forwardRef(Avatar)
})
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,54 @@ export enum AvatarSize {
type MouseEventHandler = React.MouseEventHandler<HTMLDivElement>

interface AvatarOptions {
/**
* Semantic name of the avatar.
*/
name: string

/**
* Asset image URL of the avatar.
*
* @default ''
*/
avatarUrl?: string

/**
* Fallback image URL for the avatar.
*
* @default DEFAULT_AVATAR_URL
*/
fallbackUrl?: string

/**
* Additional status type for this avatar.
* Typically, this is used to indicate the status of the user (online, offline, etc).
*
* If additional customization of the status component is needed,
* pass the custom status component as `children` of the Avatar component.
*/
status?: StatusType

/**
* Whether to display the border of the avatar.
*
* @default false
*/
showBorder?: boolean

/**
* Handler to be called when the avatar is clicked.
*/
onClick?: MouseEventHandler

/**
* Handler to be called when the mouse enters the avatar.
*/
onMouseEnter?: MouseEventHandler

/**
* Handler to be called when the mouse leaves the avatar.
*/
onMouseLeave?: MouseEventHandler
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Avatar from './Avatar'
import { Avatar } from './Avatar'
import { AvatarSize } from './Avatar.types'
import type AvatarProps from './Avatar.types'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getTitle } from 'Utils/storyUtils'
import { Avatar, AvatarSize } from 'Components/Avatars/Avatar'
import MOCK_AVATAR_LIST from './__mocks__/avatarList'
import AvatarGroupProps, { AvatarGroupEllipsisType } from './AvatarGroup.types'
import AvatarGroup from './AvatarGroup'
import { AvatarGroup } from './AvatarGroup'

const avatarSizeList = Object.keys(AvatarSize)
.filter(value => Number.isNaN(Number(value)) === true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React from 'react'
import { render } from 'Utils/testUtils'
import { Avatar } from 'Components/Avatars/Avatar'
import MOCK_AVATAR_LIST from './__mocks__/avatarList'
import AvatarGroup, { AVATAR_GROUP_TEST_ID } from './AvatarGroup'
import { AvatarGroup, AVATAR_GROUP_TEST_ID } from './AvatarGroup'
import { AvatarGroupEllipsisType } from './AvatarGroup.types'
import type AvatarGroupProps from './AvatarGroup.types'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function getProperTypoSize(avatarSize: AvatarSize) {
}[avatarSize]
}

function AvatarGroup({
export const AvatarGroup = forwardRef(function AvatarGroup({
max,
size = AvatarSize.Size24,
spacing = AVATAR_GROUP_DEFAULT_SPACING,
Expand Down Expand Up @@ -173,6 +173,4 @@ forwardedRef: React.Ref<HTMLDivElement>,
{ AvatarListComponent }
</StyledAvatarGroup>
)
}

export default forwardRef(AvatarGroup)
})
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,37 @@ export enum AvatarGroupEllipsisType {
type MouseEventHandler = React.MouseEventHandler<HTMLDivElement>

interface AvatarGroupOptions {
/**
* Maximum number of avatars to display.
*
* If the number of avatars exceeds this number, ellipsis will be displayed.
*/
max: number

/**
* Spacing between the avatars.
*
* @note Spacing could be negative, which will make the avatars overlap each other.
*
* @default 4
*/
spacing?: number

/**
* Controls how the ellipsis is displayed.
*
* @default AvatarGroupEllipsisType.Icon
*/
ellipsisType?: AvatarGroupEllipsisType

/**
* Handler to be called when the mouse enters the ellipsis area.
*/
onMouseEnterEllipsis?: MouseEventHandler

/**
* Handler to be called when the mouse leaves the ellipsis area.
*/
onMouseLeaveEllipsis?: MouseEventHandler
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import AvatarGroup from './AvatarGroup'
import { AvatarGroup } from './AvatarGroup'
import { AvatarGroupEllipsisType } from './AvatarGroup.types'
import type AvatarGroupProps from './AvatarGroup.types'

Expand Down
22 changes: 21 additions & 1 deletion packages/bezier-react/src/components/Avatars/Avatars.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import {
ArgsTable,
Canvas,
Story,
} from '@storybook/addon-docs'
import {
Avatar,
} from 'Components/Avatars/Avatar'
import {
AvatarGroup,
} from 'Components/Avatars/AvatarGroup'
import {
CheckableAvatar,
} from 'Components/Avatars/CheckableAvatar'

# Avatars

Expand Down Expand Up @@ -216,7 +226,17 @@ Avatar group에 대해 더 알아보려면 [스토리](/story/components-avatars

## API

> ✏️ TODO (`react-docgen-typescript-plugin` 적용 이후 작성)
### Avatar

<ArgsTable of={Avatar} />

### AvatarGroup

<ArgsTable of={AvatarGroup} />

### CheckableAvatar

<ArgsTable of={CheckableAvatar} />

## Version

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { Story, Meta } from '@storybook/react'
import { styled } from 'Foundation'
import { getTitle } from 'Utils/storyUtils'
import { Avatar, AvatarSize } from 'Components/Avatars/Avatar'
import { CheckableAvatar } from './CheckableAvatar'
import CheckableAvatarProps from './CheckableAvatar.types'
import CheckableAvatar from './CheckableAvatar'

const MOCK_AVATAR_URL = 'https://cf.channel.io/thumb/200x200/pub-file/1/606d87d059a6093594c0/ch-symbol-filled-smiley-bg.png'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const CHECKABLE_AVATAR_TEST_ID = 'bezier-react-checkable-avatar'

const CHECKED_DEFAULT_SEMANTIC_COLOR = 'bgtxt-green-normal'

function CheckableAvatar({
export function CheckableAvatar({
size = AvatarSize.Size24,
isChecked = false,
isCheckable = true,
Expand Down Expand Up @@ -44,5 +44,3 @@ function CheckableAvatar({
</CheckableAvatarWrapper>
)
}

export default CheckableAvatar
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import CheckableAvatar from './CheckableAvatar'
import { CheckableAvatar } from './CheckableAvatar'
import type CheckableAvatarProps from './CheckableAvatar.types'

export type {
Expand Down
83 changes: 2 additions & 81 deletions packages/bezier-react/src/components/Banner/Banner.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
ArgsTable,
Canvas,
Story,
} from '@storybook/addon-docs'
Expand Down Expand Up @@ -87,87 +88,7 @@ const renderLink = ({ content, linkTo }) => <Link to={linkTo}>{ content }</Link>

## API

- `BannerProps``BezierComponentProps`를 지원합니다.

<details>
<summary><h3>BannerVariant</h3></summary>

```ts
enum BannerVariant {
Default,
Blue,
Cobalt,
Green,
Orange,
Red,
Alt,
}
```
</details>

<details>
<summary><h3>BannerProps</h3></summary>

```ts
interface BannerProps {
/**
* The name of icon to display at the top left of the banner.
*
* If `null` is given, no icon will be displayed.
*/
icon: IconName | null

/**
* Whether to display link at the end of banner content.
*
* @default false
*/
hasLink?: boolean

/**
* The link content.
*
* This will be displayed as bold, underline text at the end of content.
*
* @remarks
* `hasLink` props should be given `true` to enable the link.
*/
linkText?: string

/**
* The location (href) of the link.
*
* By default, the link will be opened in a new tab. (`target="_blank"`)
* To specify a different behavior, use `renderLink` prop to render the link as a custom component.
*
* @remarks
* `hasLink` props should be given `true` to enable the link.
*/
linkTo?: string

/**
* Specifies how to render the link.
*
* @default
* renders link as an `<a>` tag with `target="_blank"` attribute.
*/
renderLink?: (props: {
content: ReactNode
linkTo?: string
}) => JSX.Element

/**
* Specifies which icon button to display at the top right of the banner.
*/
actionIcon?: IconName

/**
* Handler to be executed when the action icon button is clicked.
*/
onClickAction?: ButtonProps['onClick']
}
```
</details>
<ArgsTable of={Banner} />

## Version

Expand Down
Loading

0 comments on commit 34ccd70

Please sign in to comment.