Repository: arco-design/arco-design (ts)

Issue:
Form.Item的noStyle属性会导致Form的scrollToFirstError(scrollToField)属性失效
- [x] I'm sure this does not appear in [the issue list of the repository](https://github.com/arco-design/arco-design/issues)

## Basic Info 
- **Package Name And Version:** @arco-design/web-react: 2.28.0
- **System:** Mac
- **Browser:** Edge 96.0.1054.62
- **Reproduction Link:** https://codesandbox.io/s/frosty-dust-87upp?file=/index.js

## Extra info
根据源码 (https://github.com/arco-design/arco-design/blob/cf230d3abe670f835915124ede8dcad160464967/components/Form/form.tsx#L88), 发现，在跳转时计算getElementId时，获取的是Item的Wrapper id，在启用noStyle时wrapper不会创建，导致这个id找不到从而滚动失效
![image](https://user-images.githubusercontent.com/43197204/149058791-768002fa-9b17-420f-b4ff-027e6fdb1824.png)
![rQjyDqNVtS](https://user-images.githubusercontent.com/43197204/149058813-0a60ce7c-51d8-4e29-845a-85adb1ec91aa.png)


## What is expected?
点击提交，跳转至未填项目

## Steps to reproduce
点击提交，不会跳转至未填项目，注释掉noStyle（Line90）恢复滚动。


<!-- generated by arco-issue. DO NOT REMOVE -->

Pull request:
fix: form scrollToFirst not work
<!--
  Thanks so much for your PR and contribution.

  Before submitting, please make sure to follow the Pull Request Guidelines: https://github.com/arco-design/arco-design/blob/main/CONTRIBUTING.md
-->

<!-- Put an `x` in "[ ]" to check a box) -->

## Types of changes

<!-- What types of changes does this PR introduce -->
- [ ] New feature
- [x] Bug fix
- [ ] Documentation change
- [ ] Coding style change
- [ ] Component style change
- [ ] Refactoring
- [ ] Performance improvement
- [ ] Test cases
- [ ] Continuous integration
- [ ] Typescript definition change
- [ ] Breaking change
- [ ] Others 

## Background and context

<!-- Explain what problem does the PR solve -->
<!-- Link to related open issues if applicable -->

## Solution

<!-- Describe how the problem is fixed in detail -->

## How is the change tested?

<!-- Unit tests should be added/updated for bug fixes and new features, if applicable -->
<!-- Please describe how you tested the change. E.g. Creating/updating unit tests or attaching a screenshot of how it works with your change -->

## Changelog

| Component | Changelog(CN) | Changelog(EN) | Related issues |
| --------- | ------------- | ------------- | -------------- |
|      Form     |  修复 `Form` 组件的 `scrollToFirstError` 属性在设置了 `noStyle` 的表单项上失效的 bug。            |    Fixed the bug where the `scrollToFirstError` property of the `Form` component did not work on form items with `noStyle` set.           |       close #430         |

## Checklist:

- [ ] Test suite passes (`npm run test`)
- [ ] Provide changelog for relevant changes (e.g. bug fixes and new features) if applicable.
- [ ] Changes are submitted to the appropriate branch (e.g. features should be submitted to `feature` branch and others should be submitted to `main` branch)

## Other information

<!-- Please describe what other information that should be taken care of. E.g. describe the impact if introduce a breaking change -->


Patch:
diff --git a/components/Anchor/anchor.tsx b/components/Anchor/anchor.tsx
index 83462df6..03464eb5 100644
--- a/components/Anchor/anchor.tsx
+++ b/components/Anchor/anchor.tsx
@@ -175,19 +175,34 @@ function Anchor(baseProps: AnchorPropsWithChildren, ref) {
       const offset = isNumber(boundary) ? boundary : 0;
       const actions = compute(element, { block });
       if (!actions.length) return;
-      const { el, top } = actions[0];
-      const targetTop = top - offset;
-      if (!animation) {
-        // Manually trigger scrolling as browser's default action is prevented when `props.hash` is false
-        if (!willChangeHash) {
-          el.scrollTop = targetTop;
-        }
-        return;
-      }
-      slide(el as HTMLElement, targetTop, () => {
-        isScrolling.current = false;
+
+      let stopScroll = false;
+
+      const promises = actions.map(({ el, top }) => {
+        return new Promise((resolve) => {
+          if (!stopScroll) {
+            const targetTop = top - offset;
+            if (!animation) {
+              // Manually trigger scrolling as browser's default action is prevented when `props.hash` is false
+              if (!willChangeHash) {
+                el.scrollTop = targetTop;
+              }
+              return resolve(null);
+            }
+            slide(el as HTMLElement, targetTop, resolve);
+          }
+          if (!stopScroll && el === scrollContainer.current) {
+            stopScroll = true;
+          }
+
+          resolve(null);
+        });
       });
+
       isScrolling.current = true;
+      Promise.all(promises).then(() => {
+        isScrolling.current = false;
+      });
     } catch (e) {
       console.error(e);
     }
diff --git a/components/DatePicker/panels/month/index.tsx b/components/DatePicker/panels/month/index.tsx
index 97b5de02..b2183be5 100644
--- a/components/DatePicker/panels/month/index.tsx
+++ b/components/DatePicker/panels/month/index.tsx
@@ -76,7 +76,7 @@ function MonthPicker(props: InnerMonthPickerProps & PrivateCType) {
     ].map((month, index) => {
       return {
         name: CALENDAR_LOCALE.month.short[month],
-        time: dayjs(`${showYear}-${padStart(index + 1, 2, '0')}-01`),
+        time: dayjs(`${showYear}-${padStart(index + 1, 2, '0')}`, 'YYYY-MM').endOf('month'),
       };
     });
 
diff --git a/components/DatePicker/panels/year/index.tsx b/components/DatePicker/panels/year/index.tsx
index 1b724e8b..402bf0c1 100644
--- a/components/DatePicker/panels/year/index.tsx
+++ b/components/DatePicker/panels/year/index.tsx
@@ -60,7 +60,7 @@ function YearPicker(props: InnerYearPickerProps) {
       return arr.map((_, j) => {
         return {
           name: startYear + i * 3 + j,
-          time: dayjs(`${startYear + i * 3 + j}`, 'YYYY'),
+          time: dayjs(`${startYear + i * 3 + j}`, 'YYYY').endOf('year'),
           isPrev: i === 0 && j === 0,
           isNext: i === 3 && j === 2,
         };
diff --git a/components/Form/control.tsx b/components/Form/control.tsx
index da41abf7..a35fc299 100644
--- a/components/Form/control.tsx
+++ b/components/Form/control.tsx
@@ -14,7 +14,7 @@ import IconCheckCircleFill from '../../icon/react-icon/IconCheckCircleFill';
 import IconLoading from '../../icon/react-icon/IconLoading';
 import { NotifyType, StoreChangeInfo } from './store';
 import classNames from '../_util/classNames';
-import { isSyntheticEvent, schemaValidate } from './utils';
+import { isSyntheticEvent, schemaValidate, ID_SUFFIX } from './utils';
 
 function isFieldMath(field, fields) {
   const fieldObj = setWith({}, field, undefined, Object);
@@ -276,7 +276,7 @@ export default class Control<
     const child = React.Children.only(children) as ReactElement;
     const childProps: any = {
       // used by label
-      id: classNames(child.props?.id, { [`${id}_input`]: id }),
+      id: classNames(child.props?.id || { [`${id}${ID_SUFFIX}`]: id }),
     };
 
     this.getValidateTrigger().forEach((vt) => {
diff --git a/components/Form/form-label.tsx b/components/Form/form-label.tsx
index 9f1835a4..499a68c2 100644
--- a/components/Form/form-label.tsx
+++ b/components/Form/form-label.tsx
@@ -1,5 +1,6 @@
 import React from 'react';
 import { isArray, isObject } from '../_util/is';
+import { ID_SUFFIX } from './utils';
 
 import { FormItemProps } from './interface';
 
@@ -32,7 +33,7 @@ const FormItemLabel: React.FC<FormItemLabelProps> = ({
   );
 
   return label ? (
-    <label htmlFor={htmlFor && `${htmlFor}_input`}>
+    <label htmlFor={htmlFor && `${htmlFor}${ID_SUFFIX}`}>
       {symbolPosition !== 'end' && symbolNode} {label}
       {symbolPosition === 'end' && <> {symbolNode}</>}
       {showColon ? ':' : ''}
diff --git a/components/Form/form.tsx b/components/Form/form.tsx
index 433efbe2..ede9e468 100644
--- a/components/Form/form.tsx
+++ b/components/Form/form.tsx
@@ -15,6 +15,7 @@ import { FormContext as RawFormContext, FormContextType as RawFormContextType }
 import { isObject } from '../_util/is';
 import omit from '../_util/omit';
 import useMergeProps from '../_util/hooks/useMergeProps';
+import { ID_SUFFIX } from './utils';
 
 function getFormElementId<FieldKey extends KeyType = string>(
   prefix: string | undefined,
@@ -85,7 +86,11 @@ const Form = <
     if (!node) {
       return;
     }
-    const fieldNode = node.querySelector(`#${getFormElementId(id, field as string)}`);
+    let fieldNode = node.querySelector(`#${getFormElementId(id, field as string)}`);
+    if (!fieldNode) {
+      // 如果设置了nostyle， fieldNode不存在，尝试直接查询表单控件
+      fieldNode = node.querySelector(`#${getFormElementId(id, field as string)}${ID_SUFFIX}`);
+    }
     fieldNode &&
       scrollIntoView(fieldNode, {
         behavior: 'smooth',
diff --git a/components/Form/utils.tsx b/components/Form/utils.tsx
index 97ceaa18..4ca4bbae 100644
--- a/components/Form/utils.tsx
+++ b/components/Form/utils.tsx
@@ -83,3 +83,5 @@ export async function schemaValidate(field, value, _rules: RulesProps[]) {
     validate(rules[current]);
   });
 }
+
+export const ID_SUFFIX = '_input';
diff --git a/components/Select/interface.tsx b/components/Select/interface.tsx
index 6be06d7e..d107ef59 100644
--- a/components/Select/interface.tsx
+++ b/components/Select/interface.tsx
@@ -13,7 +13,7 @@ export type InputValueChangeReason =
   | 'tokenSeparator';
 
 export interface OptionInfo extends PropsWithChildren<OptionProps> {
-  child: ReactElement;
+  child?: ReactElement;
   _valid: boolean;
   _index: number;
   _origin: 'children' | 'options' | 'userCreatedOptions' | 'userCreatingOption';
@@ -216,7 +216,7 @@ export interface OptionProps
   extends Omit<HTMLAttributes<HTMLLIElement>, 'className' | 'onMouseEnter' | 'onMouseLeave'> {
   _key?: any;
   style?: CSSProperties;
-  children: ReactNode;
+  children?: ReactNode;
   prefixCls?: string;
   className?: string | string[];
   wrapperClassName?: string | string[];
diff --git a/components/Select/option.tsx b/components/Select/option.tsx
index e95cb92c..60c4c213 100644
--- a/components/Select/option.tsx
+++ b/components/Select/option.tsx
@@ -67,14 +67,14 @@ function Option(props: OptionProps, ref) {
           disabled={disabled}
           onChange={optionLabelProps.onClick}
         />
-        <span {...optionLabelProps}>{children}</span>
+        <span {...optionLabelProps}>{children??value}</span>
       </li>
     );
   }
 
   return (
     <li ref={ref} {...optionLabelProps}>
-      {children}
+      {children??value}
     </li>
   );
 }
diff --git a/site/docs/start.en-US.md b/site/docs/start.en-US.md
index 666f0ea1..6eeb69cc 100644
--- a/site/docs/start.en-US.md
+++ b/site/docs/start.en-US.md
@@ -12,7 +12,7 @@ import ACCard from '../src/widget/Card';
 <ACCard
   title="ArcoPro"
   description="Use ArcoPro to quickly build modern web pages."
-  link="/pro"
+  link="https://pro.arco.design"
   icon="ArcoPro"
   buttonText="Goto"
 />
diff --git a/site/docs/start.zh-CN.md b/site/docs/start.zh-CN.md
index fd7e1a90..e4d00f45 100644
--- a/site/docs/start.zh-CN.md
+++ b/site/docs/start.zh-CN.md
@@ -12,7 +12,7 @@ import ACCard from '../src/widget/Card';
 <ACCard
   title="ArcoPro 最佳实践"
   description="使用 ArcoPro，快速构建现代网页。"
-  link="/pro"
+  link="https://pro.arco.design"
   icon="ArcoPro"
   buttonText="立即使用"
 />
diff --git a/site/package.json b/site/package.json
index b06c6101..4fce5e00 100644
--- a/site/package.json
+++ b/site/package.json
@@ -5,8 +5,8 @@
     "@antv/g2": "^4.1.12",
     "@arco-design/arco-doc-site-components": "^1.0.0",
     "@arco-design/arco-markdown-loader": "^1.15.3",
-    "@arco-design/arco-site-footer": "^1.3.3",
-    "@arco-design/arco-site-navbar": "^1.10.11",
+    "@arco-design/arco-site-footer": "^1.3.7",
+    "@arco-design/arco-site-navbar": "^1.12.3",
     "@arco-design/arco-site-utils": "^1.0.2",
     "@babel/runtime": "^7.6.0",
     "@loadable/component": "^5.14.1",
diff --git a/site/src/App.js b/site/src/App.js
index 9909ed4b..54233294 100644
--- a/site/src/App.js
+++ b/site/src/App.js
@@ -10,7 +10,7 @@ import {
 import Home from './pages/home';
 import Customer from './pages/customer';
 import page from './page';
-import { GlobalContext } from './context';
+import { GlobalContext, GlobalNoticeContext } from './context';
 import navbarProps from './utils/navbarProps';
 import { goPath, i18nRedirect } from './utils/i18n';
 import UserNavbarBorderStyle from './hooks/useNavbarBorderStyle';
@@ -18,6 +18,7 @@ import { EventMap } from './pages/home/utils/eventMap';
 
 export default function App() {
   const { lang, theme, toggleTheme, user } = useContext(GlobalContext);
+  const { setNoticeHeight } = useContext(GlobalNoticeContext);
   const history = useHistory();
   const isHome = history.location.pathname === '/';
   const pathRef = useRef(history.location.pathname);
@@ -86,6 +87,12 @@ export default function App() {
         user={user}
         {...navbarProps}
       />
+      <Navbar.GlobalNotice
+        onHeightChange={setNoticeHeight}
+        title="Arco Design Pro"
+        desc="Arco Pro v2.0 全新上线 🎉"
+        link="https://bytedance.feishu.cn/docx/doxcneH4MAnUxcBvnLMuoywOp2f#doxcnaE2iEwuGmKcYVTvugYHveS"
+      />
       <Switch>
         <Route path="/" exact component={Home} />
         <Route path="/en-US" exact component={Home} />
diff --git a/site/src/context.js b/site/src/context.js
index 7787ac0a..5c00c99b 100644
--- a/site/src/context.js
+++ b/site/src/context.js
@@ -1,3 +1,5 @@
 import { createContext } from 'react';
 
 export const GlobalContext = createContext({});
+
+export const GlobalNoticeContext = createContext({});
diff --git a/site/src/index-en.js b/site/src/index-en.js
index e7227e57..d4b3def5 100644
--- a/site/src/index-en.js
+++ b/site/src/index-en.js
@@ -7,7 +7,7 @@ import { ConfigProvider } from '@arco-design/web-react';
 import enUS from '@arco-design/web-react/es/locale/en-US';
 import App from './App';
 import ScrollToTop from './widget/scrollTop';
-import { GlobalContext } from './context';
+import { GlobalContext, GlobalNoticeContext } from './context';
 import locale from './locale/en';
 import tea from './utils/tea';
 import './style/index.less';
@@ -18,6 +18,7 @@ const requestDomain = isProduction ? `//${location.hostname}/` : '//localhost:30
 
 function Index() {
   const [user, setUser] = useState();
+  const [noticeHeight, setNoticeHeight] = useState(0);
 
   async function getUser() {
     try {
@@ -38,7 +39,14 @@ function Index() {
         <GlobalContext.Provider value={{ lang: 'en-US', locale, user }}>
           <ScrollToTop />
           <ConfigProvider locale={enUS}>
-            <App />
+            <GlobalNoticeContext.Provider
+              value={{
+                noticeHeight,
+                setNoticeHeight,
+              }}
+            >
+              <App />
+            </GlobalNoticeContext.Provider>
           </ConfigProvider>
         </GlobalContext.Provider>
       </Navbar.NavbarThemeProvider>
diff --git a/site/src/index.js b/site/src/index.js
index 61a8e4f1..21e6ad99 100644
--- a/site/src/index.js
+++ b/site/src/index.js
@@ -7,7 +7,7 @@ import { ConfigProvider } from '@arco-design/web-react';
 import zhCN from '@arco-design/web-react/es/locale/zh-CN';
 import App from './App';
 import ScrollToTop from './widget/scrollTop';
-import { GlobalContext } from './context';
+import { GlobalContext, GlobalNoticeContext } from './context';
 import tea from './utils/tea';
 import locale from './locale/zh';
 import './style/index.less';
@@ -17,6 +17,7 @@ const requestDomain = isProduction ? `//${location.hostname}/` : '//localhost:30
 
 function Index() {
   const [user, setUser] = useState();
+  const [noticeHeight, setNoticeHeight] = useState(0);
 
   async function getUser() {
     try {
@@ -37,7 +38,14 @@ function Index() {
         <GlobalContext.Provider value={{ lang: 'zh-CN', locale, user }}>
           <ScrollToTop />
           <ConfigProvider locale={zhCN}>
-            <App />
+            <GlobalNoticeContext.Provider
+              value={{
+                noticeHeight,
+                setNoticeHeight,
+              }}
+            >
+              <App />
+            </GlobalNoticeContext.Provider>
           </ConfigProvider>
         </GlobalContext.Provider>
       </Navbar.NavbarThemeProvider>
diff --git a/site/src/page.js b/site/src/page.js
index df5ecb6d..d6e292a4 100644
--- a/site/src/page.js
+++ b/site/src/page.js
@@ -8,7 +8,7 @@ import WidgetMenu from './widget/Menu';
 import WidgetBody from './widget/Body';
 import DocAnchor from './widget/Anchor';
 import ThemeBox from './widget/ThemeBox';
-import { GlobalContext } from './context';
+import { GlobalContext, GlobalNoticeContext } from './context';
 
 const noAnchorPaths = [
   '/react',
@@ -29,6 +29,7 @@ function Components() {
 
   const { lang, locale } = useContext(GlobalContext);
   const routes = useMemo(() => getRoutes(lang, locale), [lang, locale]);
+  const { noticeHeight } = useContext(GlobalNoticeContext);
 
   const onResize = useCallback(() => {
     const windowWidth = window.innerWidth;
@@ -62,7 +63,7 @@ function Components() {
             setMenuCollapse(!menuCollapse);
           }}
         />
-        <div className="content-wrapper">
+        <div className="content-wrapper" style={{ marginTop: `${noticeHeight}px` }}>
           <WidgetBody lang={lang} routes={routes} />
           <Footer style={{ marginTop: 100 }} lang={lang} larkGroup />
         </div>
diff --git a/site/src/utils/navbarProps.js b/site/src/utils/navbarProps.js
index 712de9d2..46196b50 100644
--- a/site/src/utils/navbarProps.js
+++ b/site/src/utils/navbarProps.js
@@ -12,8 +12,8 @@ export default {
     },
   ],
   versions: [
-    { version: '1.x', link: '#' },
-    { version, link: '#' },
+    { version: '1.x', link: 'https://arco.bytedance.net/react/1.x/docs/start' },
+    { version, link: 'https://arco.design' },
   ],
   defaultVersion: version,
   loginHref: `/login?redirectUrl=${location.href}`,
diff --git a/site/src/widget/Menu/index.jsx b/site/src/widget/Menu/index.jsx
index fb8626f1..d2eed083 100644
--- a/site/src/widget/Menu/index.jsx
+++ b/site/src/widget/Menu/index.jsx
@@ -1,7 +1,8 @@
-import React, { useState, useEffect, useMemo } from 'react';
+import React, { useState, useEffect, useMemo, useContext } from 'react';
 import { Menu, Badge } from '@arco-design/web-react';
 import { useHistory } from 'react-router-dom';
 import NProgress from 'nprogress';
+import { GlobalNoticeContext } from '../../context';
 import MenuHeader from '../MenuHeader';
 import { getPath } from '../../utils/i18n';
 
@@ -37,6 +38,7 @@ function getFlattenRoutes(routes) {
 
 function ACMenu(props) {
   const { routes, style, menuCollapse, lang } = props;
+  const { noticeHeight } = useContext(GlobalNoticeContext);
   const flattenRoutes = getFlattenRoutes(routes);
   const pathname = location.pathname;
   const defaultSelectedKeys = [pathname];
@@ -86,7 +88,11 @@ function ACMenu(props) {
       className="ac-menu-wrapper"
       style={{ ...style, width, minWidth: width, maxWidth: width, opacity: width === 0 ? 0 : 1 }}
     >
-      <div id="menu" className="ac-menu" style={{ left: menuCollapse ? -261 : -1 }}>
+      <div
+        id="menu"
+        className="ac-menu"
+        style={{ left: menuCollapse ? -261 : -1, paddingTop: `${noticeHeight}px` }}
+      >
         <MenuHeader />
         <div id="menu-inner" className="ac-menu-inner">
           <Menu
diff --git a/site/yarn.lock b/site/yarn.lock
index 55070922..1e3b2b29 100644
--- a/site/yarn.lock
+++ b/site/yarn.lock
@@ -218,17 +218,17 @@
     prismjs "^1.23.0"
     react-helmet "^6.1.0"
 
-"@arco-design/arco-site-footer@^1.3.3":
-  version "1.3.3"
-  resolved "https://registry.npmjs.org/@arco-design/arco-site-footer/-/arco-site-footer-1.3.3.tgz#478e4893f0e314fd537d0b975cff93b210efb089"
-  integrity sha512-z5ZAU4Cpjkv3SW/R+9aEED+S1A5yhOG/bi1sjDGKtyHjKwGn1Tk5dWlZ7GxfD1Iiw9/ce8m9J08adDR7OPCn8Q==
+"@arco-design/arco-site-footer@^1.3.7":
+  version "1.3.7"
+  resolved "https://registry.npmjs.org/@arco-design/arco-site-footer/-/arco-site-footer-1.3.7.tgz#0c20c9bc078321c3896b0cd368d791db08a29ce9"
+  integrity sha512-13hFPOBLaZRwjhPAnTQtXImw+PvJPBmFWXNsQwP7gdGLq63cGUnlbAiNUzV/RfuEw1d47jfOTKrCS5lA7HQliQ==
   dependencies:
     classnames "^2.2.6"
 
-"@arco-design/arco-site-navbar@^1.10.11":
-  version "1.10.11"
-  resolved "https://registry.npmjs.org/@arco-design/arco-site-navbar/-/arco-site-navbar-1.10.11.tgz#7c5185cb69d6bf1bbcbf05ca6774b427e00842e5"
-  integrity sha512-63cp1e48/H1vWyzTm8YK8/6UK3r2VPhpaAUCiKhnB4uRO8gDZxoam4K32qGvVxRhlzSvsJE8ROGPb5A1O55NIg==
+"@arco-design/arco-site-navbar@^1.12.3":
+  version "1.12.3"
+  resolved "https://registry.npmjs.org/@arco-design/arco-site-navbar/-/arco-site-navbar-1.12.3.tgz#de937824b8cd0f756b75eacb561e861daed933c8"
+  integrity sha512-t9Gp9W1k7C/7zwhC/2BL5gjk7VxzXtpr9Kl4Dju0F87JTA4CnvNR7+vXjyyDgK1dC2mBeu2FAz+hB02VOj7Acw==
   dependencies:
     "@antv/g2" "^4.1.12"
     "@arco-design/arco-site-utils" "^1.0.1"


Test patch:
diff --git a/components/Form/__test__/form.test.tsx b/components/Form/__test__/form.test.tsx
index fb52af08..47339991 100644
--- a/components/Form/__test__/form.test.tsx
+++ b/components/Form/__test__/form.test.tsx
@@ -595,6 +595,6 @@ describe('ControlForm', () => {
     const label = wrapper.find('label');
 
     expect(label.getDOMNode().getAttribute('for')).toBe('a_input');
-    expect(wrapper.find('Input').getDOMNode().getAttribute('id')).toBe('input a_input');
+    expect(wrapper.find('Input').getDOMNode().getAttribute('id')).toBe('input');
   });
 });