feat(fieldset): extract content wrapper

This commit is contained in:
unix
2020-04-29 01:39:11 +08:00
parent 448648ba24
commit 1840fc225e
6 changed files with 125 additions and 15 deletions

View File

@@ -0,0 +1,41 @@
import React from 'react'
import useTheme from '../styles/use-theme'
import withDefaults from '../utils/with-defaults'
interface Props {
className?: string
}
const defaultProps = {
className: '',
}
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
export type FieldsetContentProps = Props & typeof defaultProps & NativeAttrs
const FieldsetContent: React.FC<React.PropsWithChildren<FieldsetContentProps>> = ({
className, children, ...props
}) => {
const theme = useTheme()
return (
<div className={`content ${className}`} {...props}>
{children}
<style jsx>{`
.content {
padding: ${theme.layout.gap};
}
.content :global(*:first-child) {
margin-top: 0;
}
.content :global(*:last-child) {
margin-bottom: 0;
}
`}</style>
</div>
)
}
export default withDefaults(FieldsetContent, defaultProps)

View File

@@ -35,6 +35,7 @@ const FieldsetFooter: React.FC<React.PropsWithChildren<FieldsetFooterProps>> = R
color: ${theme.palette.accents_6};
padding: ${theme.layout.gapHalf} ${theme.layout.gap};
font-size: .875rem;
min-height: 2.875rem;
box-sizing: border-box;
}
`}</style>

View File

@@ -1,9 +1,10 @@
import React, { ReactNode, useEffect, useState } from 'react'
import React, { ReactNode, useEffect, useMemo, useState } from 'react'
import useTheme from '../styles/use-theme'
import FieldsetTitle from './fieldset-title'
import FieldsetSubtitle from './fieldset-subtitle'
import FieldsetFooter from './fieldset-footer'
import FieldsetGroup from './fieldset-group'
import FieldsetContent from './fieldset-content'
import { hasChild, pickChild } from '../utils/collections'
import { useFieldset } from './fieldset-context'
import useWarning from '../utils/use-warning'
@@ -34,9 +35,11 @@ const Fieldset: React.FC<React.PropsWithChildren<FieldsetProps>> = React.memo(({
const theme = useTheme()
const { inGroup, currentValue, register } = useFieldset()
const [hidden, setHidden] = useState<boolean>(inGroup)
const hasTitle = hasChild(children, FieldsetTitle)
const hasSubtitle = hasChild(children, FieldsetSubtitle)
const [withoutFooterChildren, FooterChildren] = pickChild(children, FieldsetFooter)
const hasTitle = hasChild(withoutFooterChildren, FieldsetTitle)
const hasSubtitle = hasChild(withoutFooterChildren, FieldsetSubtitle)
const hasContent = hasChild(withoutFooterChildren, FieldsetContent)
if (inGroup) {
if (!label) {
@@ -59,13 +62,23 @@ const Fieldset: React.FC<React.PropsWithChildren<FieldsetProps>> = React.memo(({
}, [currentValue])
}
const content = useMemo(() => (
<>
{withoutFooterChildren}
{(!hasTitle && title) && (
<FieldsetTitle>{title}</FieldsetTitle>
)}
{(!hasSubtitle && subtitle) && (
<FieldsetSubtitle>{subtitle}</FieldsetSubtitle>
)}
</>
), [withoutFooterChildren, hasTitle, hasSubtitle, title, subtitle])
return (
<div className={`fieldset ${className}`} {...props}>
<div className="content">
{withoutFooterChildren}
{!hasTitle && <FieldsetTitle>{title}</FieldsetTitle>}
{!hasSubtitle && <FieldsetSubtitle>{subtitle}</FieldsetSubtitle>}
</div>
{hasContent ? content : (
<FieldsetContent>{content}</FieldsetContent>
)}
{FooterChildren && FooterChildren}
<style jsx>{`
.fieldset {
@@ -75,10 +88,6 @@ const Fieldset: React.FC<React.PropsWithChildren<FieldsetProps>> = React.memo(({
overflow: hidden;
display: ${hidden ? 'none' : 'block'};
}
.content {
padding: ${theme.layout.gap};
}
`}</style>
</div>
)
@@ -91,6 +100,8 @@ type FieldsetComponent<P = {}> = React.FC<P> & {
Subtitle: typeof FieldsetSubtitle
Footer: typeof FieldsetFooter
Group: typeof FieldsetGroup
Content: typeof FieldsetContent
Body: typeof FieldsetContent
}
type ComponentProps = Partial<typeof defaultProps> & Omit<Props, keyof typeof defaultProps> & NativeAttrs

View File

@@ -5,6 +5,7 @@ import FieldsetFooter from './fieldset-footer'
import FieldsetFooterStatus from './fieldset-footer-status'
import FieldsetFooterActions from './fieldset-footer-actions'
import FieldsetGroup from './fieldset-group'
import FieldsetContent from './fieldset-content'
FieldsetFooter.Status = FieldsetFooterStatus
FieldsetFooter.Actions = FieldsetFooterActions
@@ -12,5 +13,7 @@ Fieldset.Title = FieldsetTitle
Fieldset.Subtitle = FieldsetSubtitle
Fieldset.Footer = FieldsetFooter
Fieldset.Group = FieldsetGroup
Fieldset.Content = FieldsetContent
Fieldset.Body = FieldsetContent
export default Fieldset

View File

@@ -1,5 +1,5 @@
import { Layout, Playground, Attributes } from 'lib/components'
import { Card, Fieldset, Button, Text } from 'components'
import { Card, Fieldset, Button, Text, Divider } from 'components'
export const meta = {
title: 'fieldset',
@@ -92,6 +92,27 @@ Display a collection of related information in a single unit.
}
`} />
<Playground
title="With Divider"
desc="Use `Divider` and `Fieldset.Content` to combine different layouts."
scope={{ Fieldset, Divider }}
code={`
<Fieldset>
<Fieldset.Content style={{ paddingTop: '10pt', paddingBottom: '10pt' }}>
<h4>Prerequisites</h4>
</Fieldset.Content>
<Divider y={0} />
<Fieldset.Content>
<Fieldset.Title>Basic knowledge of HTML and CSS would also be useful.</Fieldset.Title>
<p>To get the most out of this module, you should have worked your way through the previous JavaScript modules in the series.
Those modules typically involve simple API usage, as it is often difficult to write client-side JavaScript examples without them. </p>
</Fieldset.Content>
<Fieldset.Footer>
<small>Client-side web APIs</small>
</Fieldset.Footer>
</Fieldset>
`} />
<Attributes edit="/pages/en-us/components/fieldset.mdx">
<Attributes.Title>Fieldset.Props</Attributes.Title>
@@ -103,6 +124,12 @@ Display a collection of related information in a single unit.
| **subtitle** | subtitle of fieldset | `ReactNode` / `string` | - | - |
| ... | native props | `FieldsetHTMLAttributes` | `'name', 'className', ...` | - |
<Attributes.Title alias="Fieldset.Body">Fieldset.Content.Props</Attributes.Title>
| Attribute | Description | Type | Accepted values | Default
| ---------- | ---------- | ---- | -------------- | ------ |
| ... | native props | `HTMLAttributes` | - | - |
<Attributes.Title>Fieldset.Footer.Props</Attributes.Title>
| Attribute | Description | Type | Accepted values | Default

View File

@@ -1,5 +1,5 @@
import { Layout, Playground, Attributes } from 'lib/components'
import { Card, Fieldset, Button, Text } from 'components'
import { Card, Fieldset, Button, Text, Divider } from 'components'
export const meta = {
title: '控件组 Fieldset',
@@ -49,7 +49,7 @@ export const meta = {
<Playground
title="选项卡"
desc="同时展示多个组件组"
desc="同时展示多个组件组"
scope={{ Fieldset, Button }}
code={`
() => {
@@ -91,6 +91,27 @@ export const meta = {
}
`} />
<Playground
title="组合分割线"
desc="使用 `Fieldset.Content` 与其他组件组合成不同布局。"
scope={{ Fieldset, Divider }}
code={`
<Fieldset>
<Fieldset.Content style={{ paddingTop: '10pt', paddingBottom: '10pt' }}>
<h4>预备知识</h4>
</Fieldset.Content>
<Divider y={0} />
<Fieldset.Content>
<Fieldset.Title>若知道 HTML 和 CSS 的基本知识会对理解内容大有裨益。</Fieldset.Title>
<p>若想深入理解这个单元的内容, 你必须能够以自己的能力较好地学完之前的几个章节。
这几部分涉及到了许多简单的API的使用如果没有它们我们将很难做一些实际的事情。</p>
</Fieldset.Content>
<Fieldset.Footer>
<small>客户端 Web API</small>
</Fieldset.Footer>
</Fieldset>
`} />
<Attributes edit="/pages/zh-cn/components/fieldset.mdx">
<Attributes.Title>Fieldset.Props</Attributes.Title>
@@ -102,6 +123,12 @@ export const meta = {
| **subtitle** | 副标题 | `ReactNode` / `string` | - | - |
| ... | 原生属性 | `FieldsetHTMLAttributes` | `'name', 'className', ...` | - |
<Attributes.Title alias="Fieldset.Body">Fieldset.Content.Props</Attributes.Title>
| 属性 | 描述 | 类型 | 推荐值 | 默认
| ---------- | ---------- | ---- | -------------- | ------ |
| ... | 原生属性 | `HTMLAttributes` | - | - |
<Attributes.Title>Fieldset.Footer.Props</Attributes.Title>
| 属性 | 描述 | 类型 | 推荐值 | 默认