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

Issue:
All `triggerElement` should expose current option
- [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 

## What are the similar cases of this feature
Just DX improvement, because sometimes we don't need controlled input, but we need to custom triggerElement!

## What problem does this feature solve?
Nowadays if want to custom `triggerElement` for `Select` component, the only way to get current option is storing the current option in state, so props `triggerElement` in all `Select` likes components, should expose current option, then we can access current option like `(option) => <TriggerElement.option={options} />`


<!-- generated by arco-issue. DO NOT REMOVE -->

Pull request:
feat: [Select, TreeSelect, AutoComplete] triggerElement support render-function
…r-function

<!--
  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 -->
<!-- Only support choose one type, if there are multiple types, you can add the `Type` column in the Changelog. -->

- [x] New feature
- [ ] Bug fix
- [ ] Enhancement
- [ ] Documentation change
- [ ] Coding style change
- [ ] Component style change
- [ ] Refactoring
- [ ] 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 |
| --------- | ------------- | ------------- | -------------- |
|  Select    | `Select` 组件 `triggerElement` 属性允许传入函数以自定义组件触发节点。  | `Select` component's `triggerElement` property allows passing in a function to customize the component trigger node. |       Close #641       |
|  TreeSelect    | `TreeSelect` 组件 `triggerElement` 属性允许传入函数以自定义组件触发节点。  | `TreeSelect` component's `triggerElement` property allows passing in a function to customize the component trigger node. |       Close #641       |
| AutoComplete    | `AutoComplete` 组件 `triggerElement` 属性允许传入函数以自定义组件触发节点。  | `AutoComplete` component's `triggerElement` property allows passing in a function to customize the component trigger node. |       Close #641       |

<!-- If there are multiple types, you can add the `Type` column in the Changelog, the value of the column is the same as `Types of changes` -->
## Checklist:

- [x] Test suite passes (`npm run test`)
- [x] 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/AutoComplete/README.en-US.md b/components/AutoComplete/README.en-US.md
index 405ecbfd..c1d1115f 100644
--- a/components/AutoComplete/README.en-US.md
+++ b/components/AutoComplete/README.en-US.md
@@ -26,7 +26,7 @@ An input box or custom input control, with enhanced automatic completion functio
 |error|Error style|`boolean`|`-`|-|
 |strict|Case sensitive when set `strict: true`|`boolean`|`-`|-|
 |loading|Whether the component is loading data.|`boolean`|`-`|2.10.0|
-|triggerElement|Custom trigger element|`ReactElement`|`<Input />`|-|
+|triggerElement|Custom trigger element|`ReactElement \| (({ value }) => ReactElement)`|`<Input />`|`() => ReactElement` in 2.31.0|
 |onSearch|Callback when searching items|`(value: string) => void`|`-`|-|
 |onSelect|Callback when an option is selected.|`(value: string, option: OptionInfo) => void`|`-`|-|
 |onChange|Callback when an option is selected or input value changes|`(value: string, option?: OptionInfo) => void`|`-`|-|
diff --git a/components/AutoComplete/README.zh-CN.md b/components/AutoComplete/README.zh-CN.md
index bbf9ea50..4fb68a30 100644
--- a/components/AutoComplete/README.zh-CN.md
+++ b/components/AutoComplete/README.zh-CN.md
@@ -26,7 +26,7 @@
 |error|报错状态|`boolean`|`-`|-|
 |strict|`strict: true` 的时候大小写敏感|`boolean`|`-`|-|
 |loading|是否处于加载状态。|`boolean`|`-`|2.10.0|
-|triggerElement|自定义触发元素|`ReactElement`|`<Input />`|-|
+|triggerElement|自定义触发元素|`ReactElement \| (({ value }) => ReactElement)`|`<Input />`|`() => ReactElement` in 2.31.0|
 |onSearch|搜索补全时的回调|`(value: string) => void`|`-`|-|
 |onSelect|点击补全项时的回调|`(value: string, option: OptionInfo) => void`|`-`|-|
 |onChange|输入或者点击补全项，value 改变时的回调（仅在点击补全项时存在第二个参数）|`(value: string, option?: OptionInfo) => void`|`-`|-|
diff --git a/components/AutoComplete/index.tsx b/components/AutoComplete/index.tsx
index 86fb463d..49d17e36 100644
--- a/components/AutoComplete/index.tsx
+++ b/components/AutoComplete/index.tsx
@@ -107,11 +107,13 @@ function AutoComplete(baseProps: AutoCompleteProps, ref) {
 
   useImperativeHandle(ref, () => refInput.current);
 
-  const TriggerElement = React.cloneElement(triggerElement, {
+  const usedTriggerElement =
+    typeof triggerElement === 'function' ? triggerElement({ value }) : triggerElement;
+  const TriggerElement = React.cloneElement(usedTriggerElement, {
     ref: (node) => {
       refInput.current = node;
 
-      const { ref: originRef } = triggerElement as any;
+      const { ref: originRef } = usedTriggerElement as any;
       if (typeof originRef === 'function') {
         originRef(node);
       }
diff --git a/components/AutoComplete/interface.ts b/components/AutoComplete/interface.ts
index e1f87c6d..038edfcb 100644
--- a/components/AutoComplete/interface.ts
+++ b/components/AutoComplete/interface.ts
@@ -74,8 +74,9 @@ export interface AutoCompleteProps extends PartialSelectProps {
    * @zh 自定义触发元素
    * @en Custom trigger element
    * @defaultValue <Input />
+   * @version `() => ReactElement` in 2.31.0
    */
-  triggerElement?: ReactElement;
+  triggerElement?: ReactElement | (({ value }) => ReactElement);
   /**
    * @zh 搜索补全时的回调
    * @en Callback when searching items
diff --git a/components/Select/README.en-US.md b/components/Select/README.en-US.md
index 2a2409c7..53d25a07 100644
--- a/components/Select/README.en-US.md
+++ b/components/Select/README.en-US.md
@@ -30,7 +30,7 @@ When users need to select one or more from a group of similar data, they can use
 |tokenSeparators|Separator used to tokenize on `multiple` mode.|`string[]`|`-`|-|
 |getPopupContainer|To set the container of the dropdown.|`(node: HTMLElement) => Element`|`-`|-|
 |trigger|The trigger mode which executes the dropdown action.|`TriggerProps['trigger']`|`click`|-|
-|triggerElement|The trigger element which executes the dropdown action.|`ReactNode`|`-`|-|
+|triggerElement|The trigger element which executes the dropdown action.|`\| ReactNode\| ((params: { value: any; option: OptionInfo \| OptionInfo[] }) => ReactNode)`|`-`|`() => ReactNode` in 2.31.0|
 |triggerProps|Pass all `Trigger` component properties|`Partial<TriggerProps>`|`-`|-|
 |dropdownRender|Customize dropdown content|`(menu: ReactNode) => ReactNode`|`-`|-|
 |dropdownMenuStyle|The style of dropdown menu.|`CSSProperties`|`-`|-|
diff --git a/components/Select/README.zh-CN.md b/components/Select/README.zh-CN.md
index 6bcd7477..30749ebd 100644
--- a/components/Select/README.zh-CN.md
+++ b/components/Select/README.zh-CN.md
@@ -30,7 +30,7 @@
 |tokenSeparators|在多选模式下自动分词的分隔符。|`string[]`|`-`|-|
 |getPopupContainer|弹出框挂载的父节点。|`(node: HTMLElement) => Element`|`-`|-|
 |trigger|触发方式。|`TriggerProps['trigger']`|`click`|-|
-|triggerElement|自定义触发元素。|`ReactNode`|`-`|-|
+|triggerElement|自定义触发元素。|`\| ReactNode\| ((params: { value: any; option: OptionInfo \| OptionInfo[] }) => ReactNode)`|`-`|`() => ReactNode` in 2.31.0|
 |triggerProps|可以接受所有 `Trigger` 的 `Props`|`Partial<TriggerProps>`|`-`|-|
 |dropdownRender|自定义弹出内容。|`(menu: ReactNode) => ReactNode`|`-`|-|
 |dropdownMenuStyle|下拉列表的样式。|`CSSProperties`|`-`|-|
diff --git a/components/Select/interface.tsx b/components/Select/interface.tsx
index d107ef59..ef2600f5 100644
--- a/components/Select/interface.tsx
+++ b/components/Select/interface.tsx
@@ -127,8 +127,11 @@ export interface SelectProps extends SelectViewCommonProps {
   /**
    * @zh 自定义触发元素。
    * @en The trigger element which executes the dropdown action.
+   * @version `() => ReactNode` in 2.31.0
    */
-  triggerElement?: ReactNode;
+  triggerElement?:
+    | ReactNode
+    | ((params: { value: any; option: OptionInfo | OptionInfo[] }) => ReactNode);
   /**
    * @zh 可以接受所有 `Trigger` 的 `Props`
    * @en Pass all `Trigger` component properties
diff --git a/components/Select/select.tsx b/components/Select/select.tsx
index e07a6094..42b7a68b 100644
--- a/components/Select/select.tsx
+++ b/components/Select/select.tsx
@@ -321,11 +321,18 @@ function Select(baseProps: SelectProps, ref) {
   };
 
   // Object should be returned when labelInValue is true
-  const getValueForCallbackParameter = (
-    value: SelectInnerStateValue,
-    option: OptionInfo | Array<OptionInfo>,
-    isEmpty = isEmptyValue(value, isMultipleMode)
-  ): SelectProps['value'] => {
+  const getValueAndOptionForCallback = (
+    stateValue: SelectInnerStateValue,
+    isEmpty = isEmptyValue(stateValue, isMultipleMode)
+  ): { value: SelectProps['value']; option: OptionInfo | OptionInfo[] } => {
+    let value: SelectProps['value'] = stateValue;
+    const option =
+      stateValue === undefined
+        ? undefined
+        : Array.isArray(stateValue)
+        ? stateValue.map(getOptionInfoByValue)
+        : getOptionInfoByValue(stateValue);
+
     if (labelInValue && !isEmpty) {
       const getOptionLabel = (optionValue: OptionProps['value'], optionInfo: OptionInfo) => {
         if (optionInfo) {
@@ -351,28 +358,24 @@ function Select(baseProps: SelectProps, ref) {
         }
       };
 
-      if (Array.isArray(value)) {
-        return value.map((optionValue, index) => ({
+      if (Array.isArray(stateValue)) {
+        value = stateValue.map((optionValue, index) => ({
           value: optionValue,
           label: getOptionLabel(optionValue, (option as OptionInfo[])[index]),
         }));
+      } else {
+        value = { value: stateValue, label: getOptionLabel(stateValue, option as OptionInfo) };
       }
-
-      return { value, label: getOptionLabel(value, option as OptionInfo) };
     }
-    return value;
+
+    return { option, value };
   };
 
   const tryUpdateSelectValue = (value: SelectInnerStateValue) => {
     setValue(value);
     if (onChange) {
-      const option =
-        value === undefined
-          ? undefined
-          : Array.isArray(value)
-          ? value.map(getOptionInfoByValue)
-          : getOptionInfoByValue(value);
-      onChange(getValueForCallbackParameter(value, option), option);
+      const paramsForCallback = getValueAndOptionForCallback(value);
+      onChange(paramsForCallback.value, paramsForCallback.option);
     }
   };
 
@@ -388,14 +391,14 @@ function Select(baseProps: SelectProps, ref) {
   // 多选时，取消一个选项
   const uncheckOption = (valueToRemove) => {
     // 取消选中时不需要检查option是否存在，因为可能已被外部剔除了此选项
-    const option = getOptionInfoByValue(valueToRemove);
     const newValue = (value as string[]).filter((v) => v !== valueToRemove);
     tryUpdateSelectValue(newValue);
 
     if (onDeselect) {
+      const paramsForCallback = getValueAndOptionForCallback(valueToRemove, false);
       onDeselect(
-        getValueForCallbackParameter(valueToRemove, option, false) as ReactText | LabeledValue,
-        option
+        paramsForCallback.value as ReactText | LabeledValue,
+        paramsForCallback.option as OptionInfo
       );
     }
   };
@@ -685,42 +688,45 @@ function Select(baseProps: SelectProps, ref) {
         onVisibleChange={tryUpdatePopupVisible}
         {...omit(triggerProps, ['popupVisible', 'onVisibleChange'])}
       >
-        {triggerElement || (
-          <SelectView
-            {...props}
-            {...selectViewEventHandlers}
-            ref={refSelectView}
-            // state
-            value={value}
-            inputValue={inputValue}
-            popupVisible={popupVisible}
-            // other
-            prefixCls={prefixCls}
-            isEmptyValue={isNoOptionSelected}
-            isMultiple={isMultipleMode}
-            onSort={tryUpdateSelectValue}
-            renderText={(value) => {
-              const option = getOptionInfoByValue(value);
-              let text = value;
-              if (isFunction(renderFormat)) {
-                text = renderFormat(
-                  option || null,
-                  getValueForCallbackParameter(value, option, false) as ReactText | LabeledValue
-                );
-              } else if (option) {
-                if ('children' in option) {
-                  text = option.children;
-                }
-              } else if (labelInValue && isObject(props.value)) {
-                text = (props.value as any).label;
-              }
-              return {
-                text,
-                disabled: option && option.disabled,
-              };
-            }}
-          />
-        )}
+        {typeof triggerElement === 'function'
+          ? (() => triggerElement(getValueAndOptionForCallback(value)))()
+          : triggerElement || (
+              <SelectView
+                {...props}
+                {...selectViewEventHandlers}
+                ref={refSelectView}
+                // state
+                value={value}
+                inputValue={inputValue}
+                popupVisible={popupVisible}
+                // other
+                prefixCls={prefixCls}
+                isEmptyValue={isNoOptionSelected}
+                isMultiple={isMultipleMode}
+                onSort={tryUpdateSelectValue}
+                renderText={(value) => {
+                  const option = getOptionInfoByValue(value);
+                  let text = value;
+                  if (isFunction(renderFormat)) {
+                    const paramsForCallback = getValueAndOptionForCallback(value, false);
+                    text = renderFormat(
+                      (paramsForCallback.option as OptionInfo) || null,
+                      paramsForCallback.value as ReactText | LabeledValue
+                    );
+                  } else if (option) {
+                    if ('children' in option) {
+                      text = option.children;
+                    }
+                  } else if (labelInValue && isObject(props.value)) {
+                    text = (props.value as any).label;
+                  }
+                  return {
+                    text,
+                    disabled: option && option.disabled,
+                  };
+                }}
+              />
+            )}
       </Trigger>
     </ResizeObserver>
   );
diff --git a/components/TreeSelect/README.en-US.md b/components/TreeSelect/README.en-US.md
index 6db93264..5894eadd 100644
--- a/components/TreeSelect/README.en-US.md
+++ b/components/TreeSelect/README.en-US.md
@@ -26,7 +26,7 @@ Can choose tree structure data.Only Single choice is supports.
 |treeCheckedStrategy|Customize the return value|`TreeProps['checkedStrategy']`|`all`|-|
 |treeProps|The props of the [Tree](/react/components/tree) component|`Partial<TreeProps>`|`-`|-|
 |triggerProps|The props of the `Trigger` component|`Partial<TriggerProps>`|`-`|-|
-|triggerElement|Customize the trigger element|`ReactNode`|`-`|-|
+|triggerElement|Customize the trigger element|`ReactNode \| ((params: { value: any }) => ReactNode)`|`-`|`() => ReactNode` in 2.31.0|
 |bordered|Whether show border|`boolean`|`true`|-|
 |notFoundContent|The content display when no data|`ReactNode`|`-`|-|
 |popupVisible|Whether the popup is visible or not|`boolean`|`-`|-|
diff --git a/components/TreeSelect/README.zh-CN.md b/components/TreeSelect/README.zh-CN.md
index aa467f70..6fcb9609 100644
--- a/components/TreeSelect/README.zh-CN.md
+++ b/components/TreeSelect/README.zh-CN.md
@@ -26,7 +26,7 @@
 |treeCheckedStrategy|定制回显方式|`TreeProps['checkedStrategy']`|`all`|-|
 |treeProps|可以接受所有 [Tree](/react/components/tree) 组件的参数|`Partial<TreeProps>`|`-`|-|
 |triggerProps|可以接受所有 Trigger 组件的参数|`Partial<TriggerProps>`|`-`|-|
-|triggerElement|自定义上方显示元素|`ReactNode`|`-`|-|
+|triggerElement|自定义上方显示元素|`ReactNode \| ((params: { value: any }) => ReactNode)`|`-`|`() => ReactNode` in 2.31.0|
 |bordered|是否显示边框|`boolean`|`true`|-|
 |notFoundContent|没有数据时显示的内容|`ReactNode`|`-`|-|
 |popupVisible|控制下拉框的展开收起|`boolean`|`-`|-|
diff --git a/components/TreeSelect/interface.ts b/components/TreeSelect/interface.ts
index a8d42991..eb95dca3 100644
--- a/components/TreeSelect/interface.ts
+++ b/components/TreeSelect/interface.ts
@@ -84,8 +84,9 @@ export interface TreeSelectProps extends SelectViewCommonProps {
   /**
    * @zh 自定义上方显示元素
    * @en Customize the trigger element
+   * @version `() => ReactNode` in 2.31.0
    */
-  triggerElement?: ReactNode;
+  triggerElement?: ReactNode | ((params: { value: any }) => ReactNode);
   /**
    * @zh 是否显示边框
    * @en Whether show border
diff --git a/components/TreeSelect/tree-select.tsx b/components/TreeSelect/tree-select.tsx
index d59be806..e39b240a 100644
--- a/components/TreeSelect/tree-select.tsx
+++ b/components/TreeSelect/tree-select.tsx
@@ -265,35 +265,47 @@ const TreeSelect: ForwardRefRenderFunction<
       }}
       popupVisible={popupVisible}
     >
-      {props.triggerElement || (
-        <SelectView
-          ref={refSelectView}
-          {...props}
-          popupVisible={popupVisible}
-          value={!multiple && isArray(value) ? value[0] : value}
-          inputValue={inputValue}
-          // other
-          isEmptyValue={isEmptyValue(value)}
-          prefixCls={prefixCls}
-          isMultiple={multiple}
-          renderText={renderText}
-          onRemoveCheckedItem={handleRemoveCheckedItem}
-          onClear={(e) => {
-            e.stopPropagation();
-            triggerChange([], {});
-            props.onClear && props.onClear(!!popupVisible);
-          }}
-          onKeyDown={(e) => {
-            e.stopPropagation();
-          }}
-          onFocus={(e) => {
-            e && e.stopPropagation();
-          }}
-          onChangeInputValue={(input) => {
-            setInputValue(input);
-          }}
-        />
-      )}
+      {typeof props.triggerElement === 'function'
+        ? (() => {
+            let valueForCallback;
+            if (multiple) {
+              valueForCallback = value.map((x) =>
+                props.labelInValue ? { label: x.label, value: x.value } : x.value
+              );
+            } else {
+              valueForCallback = props.labelInValue ? value[0] : value[0]?.value;
+            }
+            return props.triggerElement({ value: valueForCallback });
+          })()
+        : props.triggerElement || (
+            <SelectView
+              ref={refSelectView}
+              {...props}
+              popupVisible={popupVisible}
+              value={!multiple && isArray(value) ? value[0] : value}
+              inputValue={inputValue}
+              // other
+              isEmptyValue={isEmptyValue(value)}
+              prefixCls={prefixCls}
+              isMultiple={multiple}
+              renderText={renderText}
+              onRemoveCheckedItem={handleRemoveCheckedItem}
+              onClear={(e) => {
+                e.stopPropagation();
+                triggerChange([], {});
+                props.onClear && props.onClear(!!popupVisible);
+              }}
+              onKeyDown={(e) => {
+                e.stopPropagation();
+              }}
+              onFocus={(e) => {
+                e && e.stopPropagation();
+              }}
+              onChangeInputValue={(input) => {
+                setInputValue(input);
+              }}
+            />
+          )}
     </Trigger>
   );
 };
diff --git a/scripts/jest.config.js b/scripts/jest.config.js
index ddc626aa..bdd2ce8e 100644
--- a/scripts/jest.config.js
+++ b/scripts/jest.config.js
@@ -1,6 +1,5 @@
 // allow IDE to configure Jest config
-const config = require(require.resolve('@arco-design/arco-scripts/lib/config/jest/config.js'))
-  .default;
+const config = require(require.resolve('arco-scripts/lib/config/jest/config.js')).default;
 
 module.exports = config.client;
 // module.exports = config.node;


Test patch:
diff --git a/components/List/__test__/index.test.tsx b/components/List/__test__/index.test.tsx
index 2ba1d7a7..62b3489f 100644
--- a/components/List/__test__/index.test.tsx
+++ b/components/List/__test__/index.test.tsx
@@ -197,4 +197,17 @@ describe('List', () => {
     expect(wrapper.find('.arco-pagination .arco-select')).toHaveLength(1);
     expect(wrapper.find('.arco-list-item-content').at(0).text()).toBe('60');
   });
+
+  it('List render callback has correct parameter:index', () => {
+    const itemCount = 10;
+    const wrapper = mountList(
+      <List
+        grid={{ span: 8 }}
+        dataSource={new Array(itemCount).fill(null)}
+        bordered={false}
+        render={(_, index) => <List.Item>{index + 1}</List.Item>}
+      />
+    );
+    expect(wrapper.find('.arco-list-item-content').last().text()).toBe(`${itemCount}`);
+  });
 });
diff --git a/components/Select/__test__/index.test.tsx b/components/Select/__test__/index.test.tsx
index a5dbcd94..3194f240 100644
--- a/components/Select/__test__/index.test.tsx
+++ b/components/Select/__test__/index.test.tsx
@@ -405,4 +405,20 @@ describe('Select', () => {
     );
     expect(wrapper.find('.arco-select-option-disabled')).toHaveLength(1);
   });
+
+  it('Render triggerElement correctly', () => {
+    wrapper = mountSelect(
+      <Select
+        value="hello"
+        labelInValue
+        options={[{ value: 'hello', label: 'HELLO' }]}
+        triggerElement={({ value: { value, label } }) => (
+          <span className="custom-trigger-element">
+            {label}-{value}
+          </span>
+        )}
+      />
+    );
+    expect(wrapper.find('.custom-trigger-element').at(0).text()).toBe('HELLO-hello');
+  });
 });
diff --git a/components/Slider/__test__/index.test.tsx b/components/Slider/__test__/index.test.tsx
index 09e3ad0a..90e113ca 100644
--- a/components/Slider/__test__/index.test.tsx
+++ b/components/Slider/__test__/index.test.tsx
@@ -262,4 +262,51 @@ describe('Slider ', () => {
     expect(barStyle.right).toBe('0%');
     expect(buttonStyle.right).toBe('20%');
   });
+
+  it('support intervalConfig correctly', () => {
+    const component = mountSlider(
+      <Slider
+        marks={{ '0': '0KM', '10': '10KM', '20': '20KM', '30': '30KM' }}
+        min={0}
+        max={30}
+        getIntervalConfig={([begin, end]) => {
+          const range = `${begin}~${end}`;
+          switch (range) {
+            case '0~10':
+              return { width: '50%' };
+            default: {
+              return { step: 3 };
+            }
+          }
+        }}
+      />
+    );
+    component.find('.arco-slider-dot').at(1).simulate('mousedown');
+    expect(
+      component.find('.arco-slider-button').last().getDOMNode().getAttribute('style')
+    ).toContain('left: 50%');
+
+    component.find('.arco-slider-dot').at(2).simulate('mousedown');
+    expect(
+      component.find('.arco-slider-button').last().getDOMNode().getAttribute('style')
+    ).toContain(`left: ${0.9 * 25 + 50}%`);
+  });
+
+  it('render interval width correctly when set intervalConfig', () => {
+    const component = mountSlider(
+      <Slider
+        marks={{ '0': '0KM', '10': '10KM', '20': '20KM', '30': '30KM' }}
+        min={0}
+        max={30}
+        getIntervalConfig={() => {
+          // 3 intervals, totally 90%, need to adjust
+          return { width: 0.3 };
+        }}
+      />
+    );
+    const dots = component.find('.arco-slider-dot-wrapper');
+    expect(dots.at(1).getDOMNode().getAttribute('style')).toContain(`left: 30%`);
+    expect(dots.at(2).getDOMNode().getAttribute('style')).toContain(`left: 60%`);
+    expect(dots.at(3).getDOMNode().getAttribute('style')).toContain(`left: 100%`);
+  });
 });