11import type { CSSProperties , ExtractPropTypes , PropType } from 'vue' ;
22import {
3+ watch ,
34 defineComponent ,
45 nextTick ,
56 onBeforeUnmount ,
@@ -9,6 +10,7 @@ import {
910 ref ,
1011 computed ,
1112} from 'vue' ;
13+ import scrollIntoView from 'scroll-into-view-if-needed' ;
1214import classNames from '../_util/classNames' ;
1315import addEventListener from '../vc-util/Dom/addEventListener' ;
1416import Affix from '../affix' ;
@@ -20,13 +22,18 @@ import useStyle from './style';
2022import type { AnchorLinkProps } from './AnchorLink' ;
2123import AnchorLink from './AnchorLink' ;
2224import type { Key } from '../_util/type' ;
25+ import PropTypes from '../_util/vue-types' ;
26+ import devWarning from '../vc-util/devWarning' ;
2327
2428export interface AnchorLinkItemProps extends AnchorLinkProps {
2529 key : Key ;
2630 class ?: String ;
2731 style ?: CSSProperties ;
2832 children ?: AnchorLinkItemProps [ ] ;
2933}
34+
35+ export type AnchorDirection = 'vertical' | 'horizontal' ;
36+
3037function getDefaultContainer ( ) {
3138 return window ;
3239}
@@ -73,6 +80,7 @@ export const anchorProps = () => ({
7380 type : Array as PropType < AnchorLinkItemProps [ ] > ,
7481 default : undefined as AnchorLinkItemProps [ ] ,
7582 } ,
83+ direction : PropTypes . oneOf ( [ 'vertical' , 'horizontal' ] as AnchorDirection [ ] ) . def ( 'vertical' ) ,
7684 onChange : Function as PropType < ( currentActiveLink : string ) => void > ,
7785 onClick : Function as PropType < ( e : MouseEvent , link : { title : any ; href : string } ) => void > ,
7886} ) ;
@@ -93,6 +101,24 @@ export default defineComponent({
93101 props : anchorProps ( ) ,
94102 setup ( props , { emit, attrs, slots, expose } ) {
95103 const { prefixCls, getTargetContainer, direction } = useConfigInject ( 'anchor' , props ) ;
104+ const anchorDirection = computed ( ( ) => props . direction ?? 'vertical' ) ;
105+
106+ if ( process . env . NODE_ENV !== 'production' ) {
107+ devWarning (
108+ typeof slots . default !== 'function' ,
109+ 'Anchor' ,
110+ '`Anchor children` is deprecated. Please use `items` instead.' ,
111+ ) ;
112+ }
113+
114+ if ( process . env . NODE_ENV !== 'production' ) {
115+ devWarning (
116+ ! ( anchorDirection . value === 'horizontal' && props . items ?. some ( n => 'children' in n ) ) ,
117+ 'Anchor' ,
118+ '`Anchor items#children` is not supported when `Anchor` direction is horizontal.' ,
119+ ) ;
120+ }
121+
96122 const spanLinkNode = ref < HTMLSpanElement > ( null ) ;
97123 const anchorRef = ref ( ) ;
98124 const state = reactive < AnchorState > ( {
@@ -184,12 +210,21 @@ export default defineComponent({
184210 } ;
185211
186212 const updateInk = ( ) => {
187- const linkNode = anchorRef . value . getElementsByClassName (
188- `${ prefixCls . value } -link-title-active` ,
189- ) [ 0 ] ;
213+ const linkNode = anchorRef . value . querySelector ( `.${ prefixCls . value } -link-title-active` ) ;
190214 if ( linkNode && spanLinkNode . value ) {
191- spanLinkNode . value . style . top = `${ linkNode . offsetTop + linkNode . clientHeight / 2 } px` ;
192- spanLinkNode . value . style . height = `${ linkNode . clientHeight } px` ;
215+ const horizontalAnchor = anchorDirection . value === 'horizontal' ;
216+ spanLinkNode . value . style . top = horizontalAnchor
217+ ? ''
218+ : `${ linkNode . offsetTop + linkNode . clientHeight / 2 } px` ;
219+ spanLinkNode . value . style . height = horizontalAnchor ? '' : `${ linkNode . clientHeight } px` ;
220+ spanLinkNode . value . style . left = horizontalAnchor ? `${ linkNode . offsetLeft } px` : '' ;
221+ spanLinkNode . value . style . width = horizontalAnchor ? `${ linkNode . clientWidth } px` : '' ;
222+ if ( horizontalAnchor ) {
223+ scrollIntoView ( linkNode , {
224+ scrollMode : 'if-needed' ,
225+ block : 'nearest' ,
226+ } ) ;
227+ }
193228 }
194229 } ;
195230
@@ -210,6 +245,7 @@ export default defineComponent({
210245 handleClick : ( e , info ) => {
211246 emit ( 'click' , e , info ) ;
212247 } ,
248+ direction : anchorDirection ,
213249 } ) ;
214250
215251 onMounted ( ( ) => {
@@ -237,23 +273,31 @@ export default defineComponent({
237273 }
238274 updateInk ( ) ;
239275 } ) ;
276+
277+ watch ( [ anchorDirection , getCurrentAnchor , state . links , activeLink ] , ( ) => {
278+ updateInk ( ) ;
279+ } ) ;
280+
240281 const createNestedLink = ( options ?: AnchorLinkItemProps [ ] ) =>
241282 Array . isArray ( options )
242283 ? options . map ( item => (
243284 < AnchorLink { ...item } key = { item . key } >
244- { createNestedLink ( item . children ) }
285+ { anchorDirection . value === 'vertical' ? createNestedLink ( item . children ) : null }
245286 </ AnchorLink >
246287 ) )
247288 : null ;
289+
248290 const [ wrapSSR , hashId ] = useStyle ( prefixCls ) ;
291+
249292 return ( ) => {
250293 const { offsetTop, affix, showInkInFixed } = props ;
251294 const pre = prefixCls . value ;
252- const inkClass = classNames ( `${ pre } -ink-ball ` , {
253- [ `${ pre } -ink-ball- visible` ] : activeLink . value ,
295+ const inkClass = classNames ( `${ pre } -ink` , {
296+ [ `${ pre } -ink-visible` ] : activeLink . value ,
254297 } ) ;
255298
256299 const wrapperClass = classNames ( hashId . value , props . wrapperClass , `${ pre } -wrapper` , {
300+ [ `${ pre } -wrapper-horizontal` ] : anchorDirection . value === 'horizontal' ,
257301 [ `${ pre } -rtl` ] : direction . value === 'rtl' ,
258302 } ) ;
259303
@@ -268,9 +312,7 @@ export default defineComponent({
268312 const anchorContent = (
269313 < div class = { wrapperClass } style = { wrapperStyle } ref = { anchorRef } >
270314 < div class = { anchorClass } >
271- < div class = { `${ pre } -ink` } >
272- < span class = { inkClass } ref = { spanLinkNode } />
273- </ div >
315+ < span class = { inkClass } ref = { spanLinkNode } />
274316 { Array . isArray ( props . items ) ? createNestedLink ( props . items ) : slots . default ?.( ) }
275317 </ div >
276318 </ div >
0 commit comments