mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
chore: sync feature into next
This commit is contained in:
4
.github/workflows/preview-deploy.yml
vendored
4
.github/workflows/preview-deploy.yml
vendored
@@ -41,7 +41,9 @@ jobs:
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
if (total === 0) {
|
||||
core.setFailed('no jobs found');
|
||||
}
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}` in preview-build.yml
|
||||
// set output
|
||||
|
||||
@@ -43,7 +43,9 @@ jobs:
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
if (total === 0) {
|
||||
core.setFailed('no jobs found');
|
||||
}
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}`
|
||||
console.log('visual-diff report job status: %s', jobs['visual-diff report'].status);
|
||||
|
||||
@@ -40,7 +40,9 @@ jobs:
|
||||
}, {});
|
||||
|
||||
const total = Object.keys(jobs).length;
|
||||
if(total === 0) core.setFailed('no jobs found');
|
||||
if (total === 0) {
|
||||
core.setFailed('no jobs found');
|
||||
}
|
||||
|
||||
// the name here must be the same as `jobs.xxx.{name}`
|
||||
console.log('visual-diff report job status: %s', jobs['test image']);
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"!scripts/previewEditor/**/*",
|
||||
"!**/*.tmp",
|
||||
"!package.json",
|
||||
"!components/style/antd.css"
|
||||
"!components/style/antd.css",
|
||||
"!scripts/visual-regression/report-template.html"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
@@ -57,6 +58,7 @@
|
||||
"noExplicitAny": "off",
|
||||
"noArrayIndexKey": "off",
|
||||
"noConfusingVoidType": "off",
|
||||
"noNonNullAssertedOptionalChain": "off",
|
||||
"noThenProperty": "off",
|
||||
"noTemplateCurlyInString": "off",
|
||||
"useIterableCallbackReturn": "off"
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { act, render } from '../../../tests/utils';
|
||||
import useUniqueMemo from '../hooks/useUniqueMemo';
|
||||
|
||||
describe('Table', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('useSyncState', () => {
|
||||
const sharedObjDeps1 = {};
|
||||
const sharedObjDeps2 = {};
|
||||
|
||||
let calledTimes = 0;
|
||||
|
||||
const Test: React.FC<{ depName?: string }> = ({ depName }) => {
|
||||
useUniqueMemo(() => {
|
||||
calledTimes += 1;
|
||||
return depName;
|
||||
}, [depName, sharedObjDeps1, 'bamboo', sharedObjDeps2]);
|
||||
return null;
|
||||
};
|
||||
|
||||
// Reuse the same memo
|
||||
const { rerender } = render(
|
||||
<>
|
||||
<Test depName="light" />
|
||||
<Test depName="light" />
|
||||
<Test depName="light" />
|
||||
</>,
|
||||
);
|
||||
|
||||
expect(calledTimes).toBe(1);
|
||||
|
||||
// Different deps should clean up the cache
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(1000 * 60 * 20);
|
||||
});
|
||||
|
||||
for (let i = 0; i < 20000; i += 1) {
|
||||
rerender(<Test depName="diff" key={i} />);
|
||||
}
|
||||
rerender(<Test depName="clear" />);
|
||||
calledTimes = 0;
|
||||
|
||||
// Back should recompute
|
||||
rerender(<Test depName="light" />);
|
||||
expect(calledTimes).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const BEAT_LIMIT = 1000 * 60 * 10;
|
||||
|
||||
/**
|
||||
* A helper class to map keys to values.
|
||||
* It supports both primitive keys and object keys.
|
||||
*/
|
||||
class ArrayKeyMap<T> {
|
||||
map = new Map<string, T>();
|
||||
|
||||
// Use WeakMap to avoid memory leak
|
||||
objectIDMap = new WeakMap<object, number>();
|
||||
|
||||
nextID = 0;
|
||||
|
||||
lastAccessBeat = new Map<string, number>();
|
||||
|
||||
// We will clean up the cache when reach the limit
|
||||
accessBeat = 0;
|
||||
|
||||
set(keys: React.DependencyList, value: any) {
|
||||
// New set will trigger clear
|
||||
this.clear();
|
||||
|
||||
// Set logic
|
||||
const compositeKey = this.getCompositeKey(keys);
|
||||
this.map.set(compositeKey, value);
|
||||
this.lastAccessBeat.set(compositeKey, Date.now());
|
||||
}
|
||||
|
||||
get(keys: React.DependencyList) {
|
||||
const compositeKey = this.getCompositeKey(keys);
|
||||
|
||||
const cache = this.map.get(compositeKey);
|
||||
this.lastAccessBeat.set(compositeKey, Date.now());
|
||||
this.accessBeat += 1;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
getCompositeKey(keys: React.DependencyList) {
|
||||
const ids = keys.map<string>((key) => {
|
||||
if (key && typeof key === 'object') {
|
||||
return `obj_${this.getObjectID(key)}`;
|
||||
}
|
||||
return `${typeof key}_${key}`;
|
||||
});
|
||||
return ids.join('|');
|
||||
}
|
||||
|
||||
getObjectID(obj: object) {
|
||||
if (this.objectIDMap.has(obj)) {
|
||||
return this.objectIDMap.get(obj);
|
||||
}
|
||||
const id = this.nextID;
|
||||
this.objectIDMap.set(obj, id);
|
||||
|
||||
this.nextID += 1;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.accessBeat > 10000) {
|
||||
const now = Date.now();
|
||||
|
||||
this.lastAccessBeat.forEach((beat, key) => {
|
||||
if (now - beat > BEAT_LIMIT) {
|
||||
this.map.delete(key);
|
||||
this.lastAccessBeat.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
this.accessBeat = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueMap = new ArrayKeyMap();
|
||||
|
||||
/**
|
||||
* Like `useMemo`, but this hook result will be shared across all instances.
|
||||
*/
|
||||
function useUniqueMemo<T>(memoFn: () => T, deps: React.DependencyList) {
|
||||
return React.useMemo<T>(() => {
|
||||
const cachedValue = uniqueMap.get(deps);
|
||||
if (cachedValue) {
|
||||
return cachedValue as T;
|
||||
}
|
||||
const newValue = memoFn();
|
||||
uniqueMap.set(deps, newValue);
|
||||
return newValue;
|
||||
}, deps);
|
||||
}
|
||||
|
||||
export default useUniqueMemo;
|
||||
@@ -54,7 +54,9 @@ export interface AffixRef {
|
||||
updatePosition: ReturnType<typeof throttleByAnimationFrame>;
|
||||
}
|
||||
|
||||
type InternalAffixProps = AffixProps & { onTestUpdatePosition?: any };
|
||||
interface InternalAffixProps extends AffixProps {
|
||||
onTestUpdatePosition?: () => void;
|
||||
}
|
||||
|
||||
const Affix = React.forwardRef<AffixRef, InternalAffixProps>((props, ref) => {
|
||||
const {
|
||||
|
||||
@@ -133,7 +133,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
|
||||
fontSize: currentSize && (icon || children) ? currentSize / 2 : 18,
|
||||
}
|
||||
: {};
|
||||
}, [screens, size]);
|
||||
}, [screens, size, icon, children]);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Avatar');
|
||||
@@ -209,11 +209,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
|
||||
|
||||
childrenToRender = (
|
||||
<ResizeObserver onResize={setScaleParam}>
|
||||
<span
|
||||
className={`${prefixCls}-string`}
|
||||
ref={avatarChildrenRef}
|
||||
style={{ ...childrenStyle }}
|
||||
>
|
||||
<span className={`${prefixCls}-string`} ref={avatarChildrenRef} style={childrenStyle}>
|
||||
{children}
|
||||
</span>
|
||||
</ResizeObserver>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { VariantContext } from '../context';
|
||||
import type { ConfigProviderProps, Variant } from '../../config-provider';
|
||||
import { ConfigContext, Variants } from '../../config-provider';
|
||||
import { VariantContext } from '../context';
|
||||
|
||||
type VariantComponents = keyof Pick<
|
||||
ConfigProviderProps,
|
||||
@@ -24,8 +24,8 @@ type VariantComponents = keyof Pick<
|
||||
*/
|
||||
const useVariant = (
|
||||
component: VariantComponents,
|
||||
variant: Variant | undefined,
|
||||
legacyBordered: boolean | undefined = undefined,
|
||||
variant?: Variant,
|
||||
legacyBordered?: boolean,
|
||||
): [Variant, boolean] => {
|
||||
const { variant: configVariant, [component]: componentConfig } = React.useContext(ConfigContext);
|
||||
const ctxVariant = React.useContext(VariantContext);
|
||||
|
||||
@@ -52,7 +52,9 @@ const DirectoryTree: React.ForwardRefRenderFunction<RcTree, DirectoryTreeProps>
|
||||
const cachedSelectedKeys = React.useRef<Key[]>(null);
|
||||
|
||||
const getInitExpandedKeys = () => {
|
||||
const { keyEntities } = convertDataToEntities(getTreeData(props));
|
||||
const { keyEntities } = convertDataToEntities(getTreeData(props), {
|
||||
fieldNames: props.fieldNames,
|
||||
});
|
||||
|
||||
let initExpandedKeys: Key[];
|
||||
|
||||
|
||||
@@ -320,6 +320,10 @@ describe('Directory Tree', () => {
|
||||
fieldNames: { key: 'id', title: 'label', children: 'child' },
|
||||
}),
|
||||
);
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/55418
|
||||
expect(container.querySelectorAll('.ant-tree-node-content-wrapper-open').length).toBe(2);
|
||||
|
||||
fireEvent.click(container.querySelectorAll('.ant-tree-node-content-wrapper')[0]);
|
||||
expect(onSelect.mock.calls[0][1].selectedNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -300,11 +300,9 @@
|
||||
"react-highlight-words": "^0.21.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-intersection-observer": "^9.16.0",
|
||||
"react-resizable": "^3.0.5",
|
||||
"react-router-dom": "^7.9.3",
|
||||
"react-sticky-box": "^2.0.5",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"rehype-stringify": "^10.0.1",
|
||||
"remark": "^15.0.1",
|
||||
"remark-cli": "^12.0.1",
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
{{reportContent}}
|
||||
|
||||
<script>
|
||||
window.addEventListener('click', function (e) {
|
||||
window.addEventListener('click', (e) => {
|
||||
if (e.target.tagName === 'FIGCAPTION') {
|
||||
// get previous sibling
|
||||
const img = e.target.previousElementSibling;
|
||||
|
||||
@@ -292,7 +292,7 @@ export function imageDemoTest(component: string, options: Options = {}) {
|
||||
(file) => !file.includes('_semantic'),
|
||||
);
|
||||
|
||||
const mobileDemos: [file: string, node: any][] = [];
|
||||
const mobileDemos: [file: string, node: React.ReactElement<any>][] = [];
|
||||
|
||||
const getTestOption = (file: string) => ({
|
||||
onlyViewport:
|
||||
|
||||
Reference in New Issue
Block a user