1
0
Эх сурвалжийг харах

fix: Anchor spacing in front of anchor text cannot trigger selection

edc-hui 3 жил өмнө
parent
commit
02a67aae6b

+ 0 - 1
packages/semi-foundation/anchor/anchor.scss

@@ -65,7 +65,6 @@ $module: #{$prefix}-anchor;
     }
 
     &-link {
-        padding-left: $spacing-anchor_link-paddingLeft;
 
         &-wrapper {
             padding-right: $width-anchor-outline;

+ 0 - 1
packages/semi-foundation/anchor/rtl.scss

@@ -11,7 +11,6 @@ $module: #{$prefix}-anchor;
         }
 
         &-link {
-            padding-right: $spacing-anchor_link-paddingLeft;
             padding-left: auto;
         }
     }

+ 39 - 7
packages/semi-ui/anchor/index.tsx

@@ -10,10 +10,12 @@ import '@douyinfe/semi-foundation/anchor/anchor.scss';
 import { noop, debounce, throttle } from 'lodash';
 import getUuid from '@douyinfe/semi-foundation/utils/uuid';
 import { ArrayElement } from '../_base/base';
+import ConfigContext, { ContextValue } from '../configProvider/context';
 
 const prefixCls = cssClasses.PREFIX;
 
 export { LinkProps } from './link';
+
 export interface AnchorProps {
     autoCollapse?: boolean;
     className?: string;
@@ -44,6 +46,7 @@ export interface AnchorState {
 }
 
 class Anchor extends BaseComponent<AnchorProps, AnchorState> {
+    static contextType = ConfigContext;
     static Link = Link;
     static PropTypes = {
         size: PropTypes.oneOf(strings.SIZE),
@@ -88,6 +91,7 @@ class Anchor extends BaseComponent<AnchorProps, AnchorState> {
     childMap: Record<string, Set<string>>;
     handler: () => void;
     clickHandler: () => void;
+    context: ContextValue;
 
     constructor(props: AnchorProps) {
         super(props);
@@ -96,7 +100,7 @@ class Anchor extends BaseComponent<AnchorProps, AnchorState> {
             links: [],
             clickLink: false,
             scrollHeight: '100%',
-            slideBarTop: '0'
+            slideBarTop: '0',
         };
 
         this.foundation = new AnchorFoundation(this.adapter);
@@ -107,9 +111,7 @@ class Anchor extends BaseComponent<AnchorProps, AnchorState> {
         return {
             ...super.adapter,
             addLink: value => {
-                this.setState(prevState => (
-                    { links: [...prevState.links, value] }
-                ));
+                this.setState(prevState => ({ links: [...prevState.links, value] }));
             },
             removeLink: link => {
                 this.setState(prevState => {
@@ -218,6 +220,28 @@ class Anchor extends BaseComponent<AnchorProps, AnchorState> {
         this.foundation.updateChildMap(prevState, state);
     };
 
+    renderChildren = () => {
+        const loop = (children, level = 1) => {
+            return React.Children.map(children, child => {
+                if (React.isValidElement(child)) {
+                    const childProps = {
+                        direction: this.context.direction,
+                        level,
+                        children: [],
+                    };
+                    const { children } = child.props as any;
+                    const hasChildren = children && React.Children.count(children) > 0;
+                    if (hasChildren) {
+                        childProps.children = loop(children, level + 1);
+                    }
+                    return React.cloneElement(child, childProps);
+                }
+                return null;
+            });
+        };
+        return loop(this.props.children);
+    };
+
     componentDidMount() {
         const { defaultAnchor = '' } = this.props;
         this.anchorID = getUuid('semi-anchor').replace('.', '');
@@ -286,15 +310,23 @@ class Anchor extends BaseComponent<AnchorProps, AnchorState> {
                     removeLink: this.removeLink,
                 }}
             >
-                <div role="navigation" aria-label={ ariaLabel || 'Side navigation'} className={wrapperCls} style={wrapperStyle} id={this.anchorID}>
+                <div
+                    role="navigation"
+                    aria-label={ariaLabel || 'Side navigation'}
+                    className={wrapperCls}
+                    style={wrapperStyle}
+                    id={this.anchorID}
+                >
                     <div aria-hidden className={slideCls} style={{ height: scrollHeight }}>
                         <span className={slideBarCls} style={{ top: slideBarTop }} />
                     </div>
-                    <div className={anchorWrapper} role="list">{children}</div>
+                    <div className={anchorWrapper} role="list">
+                        {this.renderChildren()}
+                    </div>
                 </div>
             </AnchorContext.Provider>
         );
     }
 }
 
-export default Anchor;
+export default Anchor;

+ 11 - 2
packages/semi-ui/anchor/link.tsx

@@ -16,6 +16,8 @@ export interface LinkProps {
     children?: ReactNode;
     style?: React.CSSProperties;
     disabled?: boolean;
+    level?: number;
+    direction?: 'ltr' | 'rtl';
 }
 
 // eslint-disable-next-line @typescript-eslint/ban-types
@@ -38,6 +40,7 @@ export default class Link extends BaseComponent<LinkProps, {}> {
     foundation: LinkFoundation;
 
     context!: AnchorContextType;
+
     constructor(props: LinkProps) {
         super(props);
         this.foundation = new LinkFoundation(this.adapter);
@@ -120,11 +123,13 @@ export default class Link extends BaseComponent<LinkProps, {}> {
         if (!this.context.autoCollapse) {
             return <div role="list">{children}</div>;
         }
-        return activeLink === href || (childMap[href] && childMap[href].has(activeLink)) ? <div role="list">{children}</div> : null;
+        return activeLink === href || (childMap[href] && childMap[href].has(activeLink)) ? (
+            <div role="list">{children}</div>
+        ) : null;
     };
 
     render() {
-        const { href, className, style, disabled = false, title } = this.props;
+        const { href, className, style, disabled = false, title, level, direction } = this.props;
         const { activeLink, showTooltip } = this.context;
         const active = activeLink === href;
         const linkCls = cls(`${prefixCls}-link`, className);
@@ -132,8 +137,12 @@ export default class Link extends BaseComponent<LinkProps, {}> {
             [`${prefixCls}-link-title-active`]: active,
             [`${prefixCls}-link-title-disabled`]: disabled,
         });
+        const paddingAttributeKey = direction === 'rtl' ? 'paddingRight' : 'paddingLeft';
         const ariaProps = {
             'aria-disabled': disabled,
+            style: {
+                [paddingAttributeKey]: 8 * level,
+            },
         };
         if (active) {
             ariaProps['aria-details'] = 'active';