Repository: ant-design/ant-design-mobile
Pull request #5448 (2022-07-06 04:10:39)

enhance(NoticeBar): adjust the clickable area of close icon

github-actions[bot]: PR preview has been successfully built and deployed to https://antd-mobile-preview-pr-5448.surge.sh

Patch:
diff --git a/src/components/calendar/calendar.tsx b/src/components/calendar/calendar.tsx
index 1259c44f0..bb9ff8f11 100644
--- a/src/components/calendar/calendar.tsx
+++ b/src/components/calendar/calendar.tsx
@@ -72,7 +72,7 @@ const defaultProps = {
   nextYearButton: <ArrowLeftDouble />,
 }
 
-export const Calendar = forwardRef<CalenderRef, CalendarProps>((p, ref) => {
+export const Calendar = forwardRef<CalendarRef, CalendarProps>((p, ref) => {
   const today = dayjs()
   const props = mergeProps(defaultProps, p)
   const { locale } = useConfig()
diff --git a/src/components/form/form-item.tsx b/src/components/form/form-item.tsx
index 61c24128d..7fad6b990 100644
--- a/src/components/form/form-item.tsx
+++ b/src/components/form/form-item.tsx
@@ -1,6 +1,6 @@
 import React, { FC, useContext, useCallback, useState, useRef } from 'react'
 import classNames from 'classnames'
-import { NativeProps } from '../../utils/native-props'
+import { NativeProps, withNativeProps } from '../../utils/native-props'
 import { Field, FormInstance } from 'rc-field-form'
 import type { FieldProps } from 'rc-field-form/lib/Field'
 import FieldContext from 'rc-field-form/lib/FieldContext'
@@ -91,7 +91,7 @@ type FormItemLayoutProps = Pick<
   errors: string[]
   warnings: string[]
   children: React.ReactNode
-}
+} & NativeProps
 
 const FormItemLayout: React.FC<FormItemLayoutProps> = props => {
   const {
@@ -193,7 +193,8 @@ const FormItemLayout: React.FC<FormItemLayoutProps> = props => {
       </>
     ) : null
 
-  return (
+  return withNativeProps(
+    props,
     <List.Item
       style={style}
       title={layout === 'vertical' && labelElement}
@@ -324,7 +325,8 @@ export const FormItem: FC<FormItemProps> = props => {
       curWarnings
     )
 
-    return (
+    return withNativeProps(
+      props,
       <FormItemLayout
         className={className}
         style={style}
diff --git a/src/components/notice-bar/notice-bar.less b/src/components/notice-bar/notice-bar.less
index faff2f53f..f87938f11 100644
--- a/src/components/notice-bar/notice-bar.less
+++ b/src/components/notice-bar/notice-bar.less
@@ -67,6 +67,16 @@
     flex-shrink: 0;
     margin-left: 12px;
   }
+
+  &-close {
+    width: 24px;
+    height: 24px;
+    margin-right: -3px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
   &-close-icon {
     font-size: var(--adm-font-size-10);
   }
diff --git a/src/components/notice-bar/notice-bar.tsx b/src/components/notice-bar/notice-bar.tsx
index 0a28e84ab..cf7d16a63 100644
--- a/src/components/notice-bar/notice-bar.tsx
+++ b/src/components/notice-bar/notice-bar.tsx
@@ -131,13 +131,15 @@ export const NoticeBar = memo<NoticeBarProps>(p => {
         <span className={`${classPrefix}-right`}>
           {props.extra}
           {props.closeable && (
-            <CloseOutline
-              className={`${classPrefix}-close-icon`}
+            <div
+              className={`${classPrefix}-close`}
               onClick={() => {
                 setVisible(false)
                 props.onClose?.()
               }}
-            />
+            >
+              <CloseOutline className={`${classPrefix}-close-icon`} />
+            </div>
           )}
         </span>
       )}
diff --git a/src/components/tabs/demos/demo4.less b/src/components/tabs/demos/demo4.less
index 06329d45a..1633d3cc7 100644
--- a/src/components/tabs/demos/demo4.less
+++ b/src/components/tabs/demos/demo4.less
@@ -2,7 +2,7 @@
   position: sticky;
   top: 0;
   z-index: 100;
-  background: #ffffff;
+  background: var(--adm-color-background);
 }
 
 .content {
diff --git a/src/utils/merge-locale.ts b/src/utils/merge-locale.ts
index 761a4abc1..9f39965d6 100644
--- a/src/utils/merge-locale.ts
+++ b/src/utils/merge-locale.ts
@@ -1,6 +1,23 @@
-import cloneDeep from 'lodash/cloneDeep'
-import merge from 'lodash/merge'
-
-export function mergeLocale<T, P>(base: T, patch: P): T {
-  return merge(cloneDeep(base), patch)
+export function mergeLocale<T extends object, P extends object>(
+  base: T,
+  patch: P
+): T {
+  function merge(a: any, b: any): any {
+    if (
+      typeof a !== 'object' ||
+      typeof b !== 'object' ||
+      Array.isArray(a) ||
+      Array.isArray(b)
+    ) {
+      return b !== undefined ? b : a
+    }
+    const result: any = {}
+    for (const key in a) {
+      if (a.hasOwnProperty(key)) {
+        result[key] = merge(a[key], b[key])
+      }
+    }
+    return result
+  }
+  return merge(base, patch)
 }
diff --git a/src/utils/with-default-props.tsx b/src/utils/with-default-props.tsx
index 7f3ef30bd..178027200 100644
--- a/src/utils/with-default-props.tsx
+++ b/src/utils/with-default-props.tsx
@@ -1,15 +1,13 @@
-import assign from 'lodash/assign'
 import assignWith from 'lodash/assignWith'
-import isUndefined from 'lodash/isUndefined'
 
 export function mergeProps<A, B>(a: A, b: B): B & A
 export function mergeProps<A, B, C>(a: A, b: B, c: C): C & B & A
 export function mergeProps(...items: any[]) {
   function customizer(objValue: any, srcValue: any) {
-    return isUndefined(srcValue) ? objValue : srcValue
+    return srcValue === undefined ? objValue : srcValue
   }
 
-  let ret = assign({}, items[0])
+  let ret = { ...items[0] }
   for (let i = 1; i < items.length; i++) {
     ret = assignWith(ret, items[i], customizer)
   }


Test patch:
diff --git a/src/components/calendar/tests/calendar.test.tsx b/src/components/calendar/tests/calendar.test.tsx
index 652b6a44e..ac572c53f 100644
--- a/src/components/calendar/tests/calendar.test.tsx
+++ b/src/components/calendar/tests/calendar.test.tsx
@@ -1,6 +1,6 @@
 import React, { useState, useRef } from 'react'
 import { render, testA11y, fireEvent } from 'testing'
-import Calendar, { CalenderRef } from '..'
+import Calendar, { CalendarRef } from '..'
 import dayjs from 'dayjs'
 import MockDate from 'mockdate'
 
@@ -99,7 +99,7 @@ describe('Calendar', () => {
 
   test('jump to a day', async () => {
     const App = () => {
-      const ref = useRef<CalenderRef>(null)
+      const ref = useRef<CalendarRef>(null)
       return (
         <>
           <button
diff --git a/src/components/selector/tests/selector.test.tsx b/src/components/selector/tests/selector.test.tsx
new file mode 100644
index 000000000..2eb12bf1d
--- /dev/null
+++ b/src/components/selector/tests/selector.test.tsx
@@ -0,0 +1,97 @@
+import React from 'react'
+import { render, testA11y, fireEvent, screen } from 'testing'
+import Selector from '..'
+import { options } from '../demos/options'
+
+const classPrefix = `adm-selector`
+
+describe('Selector', () => {
+  test('a11y', async () => {
+    await testA11y(<Selector options={options} />)
+  })
+
+  test('onChange should be work', () => {
+    const onChange = jest.fn()
+    render(<Selector options={options} onChange={onChange} />)
+
+    const label = screen.getByText(options[1].label)
+    fireEvent.click(label)
+    expect(label).toHaveClass(`${classPrefix}-item-active`)
+    expect(onChange.mock.calls[0][0]).toMatchObject([options[1].value])
+    expect(onChange.mock.calls[0][1].items).toMatchObject([options[1]])
+  })
+
+  test('disabled should be work', () => {
+    const onChange = jest.fn()
+    render(
+      <Selector
+        options={[
+          {
+            label: '1',
+            value: '1',
+            disabled: true,
+          },
+        ]}
+        onChange={onChange}
+      />
+    )
+
+    const label = screen.getByText('1')
+    expect(label).toHaveClass(`${classPrefix}-item-disabled`)
+    fireEvent.click(label)
+    expect(onChange).not.toBeCalled()
+  })
+
+  test('renders with columns', () => {
+    render(<Selector columns={2} options={options} />)
+    expect(document.querySelectorAll('.adm-grid')[0]).toBeInTheDocument()
+  })
+
+  test('multiple should be work', () => {
+    render(<Selector options={options} multiple />)
+    const label1 = screen.getByText(options[0].label)
+    const label2 = screen.getByText(options[1].label)
+    fireEvent.click(label1)
+    expect(label1).toHaveClass(`${classPrefix}-item-multiple-active`)
+    fireEvent.click(label2)
+    expect(label2).toHaveClass(`${classPrefix}-item-multiple-active`)
+    expect(
+      document.querySelectorAll(`.${classPrefix}-item-multiple-active`)
+    ).toHaveLength(2)
+
+    fireEvent.click(label1)
+    expect(
+      document.querySelectorAll(`.${classPrefix}-item-multiple-active`)
+    ).toHaveLength(1)
+  })
+
+  test('renders with description', () => {
+    render(
+      <Selector
+        options={[
+          {
+            label: '1',
+            value: '1',
+            description: 'desc',
+          },
+        ]}
+      />
+    )
+    expect(screen.getByText('desc')).toBeInTheDocument()
+  })
+
+  test('renders without check mark', () => {
+    render(
+      <Selector
+        options={options}
+        showCheckMark={false}
+        defaultValue={[options[0].value]}
+      />
+    )
+    const label = screen.getByText(options[0].label)
+    expect(label).toHaveClass(`${classPrefix}-item-active`)
+    expect(
+      document.querySelectorAll(`.${classPrefix}check-mark-wrapper`)
+    ).toHaveLength(0)
+  })
+})