From d7df147240d6e928ce62332e1f0c7b8f2c809e68 Mon Sep 17 00:00:00 2001 From: Yuki Zhang Date: Wed, 30 Nov 2022 15:55:43 +0800 Subject: [PATCH] feat: Anchor component changed to data-driven (#39034) * feat: Anchor component changed to data-driven * test: add test cases for data driven items * fix: type * chore: mark deprecated for anchor children prop * docs: add items description * test: update snapshot * docs: demos changed to data-driven * docs: Keep the old jsx syntax demo for debugging --- components/anchor/Anchor.tsx | 29 ++++++- components/anchor/AnchorLink.tsx | 7 +- components/anchor/__tests__/Anchor.test.tsx | 60 ++++++++++++++ .../__snapshots__/Anchor.test.tsx.snap | 81 +++++++++++++++++++ .../__snapshots__/demo-extend.test.ts.snap | 80 ++++++++++++++++++ .../__tests__/__snapshots__/demo.test.ts.snap | 80 ++++++++++++++++++ components/anchor/demo/customizeHighlight.tsx | 43 +++++++--- components/anchor/demo/legacy-anchor.md | 7 ++ components/anchor/demo/legacy-anchor.tsx | 17 ++++ components/anchor/demo/onChange.tsx | 43 +++++++--- components/anchor/demo/onClick.tsx | 43 +++++++--- components/anchor/demo/static.tsx | 42 +++++++--- 12 files changed, 489 insertions(+), 43 deletions(-) create mode 100644 components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap create mode 100644 components/anchor/demo/legacy-anchor.md create mode 100644 components/anchor/demo/legacy-anchor.tsx diff --git a/components/anchor/Anchor.tsx b/components/anchor/Anchor.tsx index 1122dfcb78a4..6ca13b070134 100644 --- a/components/anchor/Anchor.tsx +++ b/components/anchor/Anchor.tsx @@ -6,10 +6,18 @@ import type { ConfigConsumerProps } from '../config-provider'; import { ConfigContext } from '../config-provider'; import getScroll from '../_util/getScroll'; import scrollTo from '../_util/scrollTo'; +import warning from '../_util/warning'; import AnchorContext from './context'; +import type { AnchorLinkBaseProps } from './AnchorLink'; +import AnchorLink from './AnchorLink'; import useStyle from './style'; +export interface AnchorLinkItemProps extends AnchorLinkBaseProps { + key: React.Key; + children?: AnchorLinkItemProps[]; +} + export type AnchorContainer = HTMLElement | Window; function getDefaultContainer() { @@ -45,6 +53,9 @@ export interface AnchorProps { prefixCls?: string; className?: string; style?: React.CSSProperties; + /** + * @deprecated Please use `items` instead. + */ children?: React.ReactNode; offsetTop?: number; bounds?: number; @@ -61,6 +72,7 @@ export interface AnchorProps { targetOffset?: number; /** Listening event when scrolling change active link */ onChange?: (currentActiveLink: string) => void; + items?: AnchorLinkItemProps[]; } interface InternalAnchorProps extends AnchorProps { @@ -100,6 +112,7 @@ const AnchorContent: React.FC = (props) => { affix = true, showInkInFixed = false, children, + items, bounds, targetOffset, onClick, @@ -108,6 +121,11 @@ const AnchorContent: React.FC = (props) => { getCurrentAnchor, } = props; + // =================== Warning ===================== + if (process.env.NODE_ENV !== 'production') { + warning(!children, 'Anchor', '`Anchor children` is deprecated. Please use `items` instead.'); + } + const [links, setLinks] = React.useState([]); const [activeLink, setActiveLink] = React.useState(null); const activeLinkRef = React.useRef(activeLink); @@ -257,13 +275,22 @@ const AnchorContent: React.FC = (props) => { ...style, }; + const createNestedLink = (options?: AnchorLinkItemProps[]) => + Array.isArray(options) + ? options.map((item) => ( + + {createNestedLink(item.children)} + + )) + : null; + const anchorContent = (
- {children} + {'items' in props ? createNestedLink(items) : children}
); diff --git a/components/anchor/AnchorLink.tsx b/components/anchor/AnchorLink.tsx index 5afba519b0d4..0ea729e0bd07 100644 --- a/components/anchor/AnchorLink.tsx +++ b/components/anchor/AnchorLink.tsx @@ -5,15 +5,18 @@ import { ConfigConsumer } from '../config-provider'; import type { AntAnchor } from './Anchor'; import AnchorContext from './context'; -export interface AnchorLinkProps { +export interface AnchorLinkBaseProps { prefixCls?: string; href: string; target?: string; title: React.ReactNode; - children?: React.ReactNode; className?: string; } +export interface AnchorLinkProps extends AnchorLinkBaseProps { + children?: React.ReactNode; +} + const AnchorLink: React.FC = (props) => { const { href = '#', title, prefixCls: customizePrefixCls, children, className, target } = props; diff --git a/components/anchor/__tests__/Anchor.test.tsx b/components/anchor/__tests__/Anchor.test.tsx index aa47e56c3c9a..c4468742d522 100644 --- a/components/anchor/__tests__/Anchor.test.tsx +++ b/components/anchor/__tests__/Anchor.test.tsx @@ -432,4 +432,64 @@ describe('Anchor Render', () => { }).not.toThrow(); }); }); + + it('renders items correctly', () => { + const { container, asFragment } = render( + , + ); + expect(container.querySelectorAll('.ant-anchor .ant-anchor-link').length).toBe(5); + const linkTitles = Array.from(container.querySelector('.ant-anchor')?.childNodes!) + .slice(1) + .map((n) => (n as HTMLElement).querySelector('.ant-anchor-link-title')); + expect((linkTitles[0] as HTMLAnchorElement).href).toContain('#components-anchor-demo-basic'); + expect((linkTitles[1] as HTMLAnchorElement).href).toContain('#components-anchor-demo-static'); + expect((linkTitles[2] as HTMLAnchorElement).href).toContain('#api'); + expect(asFragment().firstChild).toMatchSnapshot(); + expect( + ( + container.querySelector( + '.ant-anchor .ant-anchor-link .ant-anchor-link .ant-anchor-link-title', + ) as HTMLAnchorElement + )?.href, + ).toContain('#anchor-props'); + expect( + ( + container.querySelector( + '.ant-anchor .ant-anchor-link .ant-anchor-link .ant-anchor-link .ant-anchor-link-title', + ) as HTMLAnchorElement + )?.href, + ).toContain('#link-props'); + }); }); diff --git a/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap b/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap new file mode 100644 index 000000000000..9fddec286671 --- /dev/null +++ b/components/anchor/__tests__/__snapshots__/Anchor.test.tsx.snap @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Anchor Render renders items correctly 1`] = ` + +`; diff --git a/components/anchor/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/anchor/__tests__/__snapshots__/demo-extend.test.ts.snap index e214cd303541..906b661c626e 100644 --- a/components/anchor/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/anchor/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -156,6 +156,86 @@ exports[`renders ./components/anchor/demo/customizeHighlight.tsx extend context `; +exports[`renders ./components/anchor/demo/legacy-anchor.tsx extend context correctly 1`] = ` + +`; + exports[`renders ./components/anchor/demo/onChange.tsx extend context correctly 1`] = `
`; +exports[`renders ./components/anchor/demo/legacy-anchor.tsx correctly 1`] = ` + +`; + exports[`renders ./components/anchor/demo/onChange.tsx correctly 1`] = `
'#components-anchor-demo-static'; const App: React.FC = () => ( - - - - - - - - + ); export default App; diff --git a/components/anchor/demo/legacy-anchor.md b/components/anchor/demo/legacy-anchor.md new file mode 100644 index 000000000000..775eb63223dd --- /dev/null +++ b/components/anchor/demo/legacy-anchor.md @@ -0,0 +1,7 @@ +## zh-CN + +Debug usage + +## en-US + +Debug usage diff --git a/components/anchor/demo/legacy-anchor.tsx b/components/anchor/demo/legacy-anchor.tsx new file mode 100644 index 000000000000..2280a74ec90f --- /dev/null +++ b/components/anchor/demo/legacy-anchor.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Anchor } from 'antd'; + +const { Link } = Anchor; + +const App: React.FC = () => ( + + + + + + + + +); + +export default App; diff --git a/components/anchor/demo/onChange.tsx b/components/anchor/demo/onChange.tsx index f87d1703bb5c..da2f7b587e6b 100644 --- a/components/anchor/demo/onChange.tsx +++ b/components/anchor/demo/onChange.tsx @@ -1,21 +1,44 @@ import React from 'react'; import { Anchor } from 'antd'; -const { Link } = Anchor; - const onChange = (link: string) => { console.log('Anchor:OnChange', link); }; const App: React.FC = () => ( - - - - - - - - + ); export default App; diff --git a/components/anchor/demo/onClick.tsx b/components/anchor/demo/onClick.tsx index ddf88d865fcb..4f9866572db8 100644 --- a/components/anchor/demo/onClick.tsx +++ b/components/anchor/demo/onClick.tsx @@ -1,8 +1,6 @@ import React from 'react'; import { Anchor } from 'antd'; -const { Link } = Anchor; - const handleClick = ( e: React.MouseEvent, link: { @@ -15,14 +13,39 @@ const handleClick = ( }; const App: React.FC = () => ( - - - - - - - - + ); export default App; diff --git a/components/anchor/demo/static.tsx b/components/anchor/demo/static.tsx index a5dabdc510cd..be2d34c05303 100644 --- a/components/anchor/demo/static.tsx +++ b/components/anchor/demo/static.tsx @@ -1,17 +1,39 @@ import React from 'react'; import { Anchor } from 'antd'; -const { Link } = Anchor; - const App: React.FC = () => ( - - - - - - - - + ); export default App;