Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 84 additions & 2 deletions packages/semi-ui/_base/baseComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { DefaultAdapter } from '@douyinfe/semi-foundation/base/foundation';
import { VALIDATE_STATUS } from '@douyinfe/semi-foundation/base/constants';
import getDataAttr from '@douyinfe/semi-foundation/utils/getDataAttr';
import { ArrayElement } from './base';
import { without } from "lodash";

const { hasOwnProperty } = Object.prototype;

Expand All @@ -19,14 +20,71 @@ export interface BaseProps {
children?: ReactNode | undefined | any
}


export enum SemiUsedEvent {
Click = "click",
MouseDown = "mousedown",
MouseUp = "mouseup",
Scroll = "scroll",
TouchEnd = "touchend",
Resize = "resize",
KeyDown = "keydown",
TouchMove = "touchmove"
}

type SemiEventTarget = typeof window | typeof document;

type Callback = (e: Event) => void

let isInited = false;

// eslint-disable-next-line
export default class BaseComponent<P extends BaseProps = {}, S = {}> extends Component<P, S> {
static propTypes = {};

static defaultProps = {};
static windowEventWeakMap: Record<string, WeakRef<Callback>[]> = {}
static documentEventWeakMap: Record<string, WeakRef<Callback & {_function?: Callback}>[]> = {}
static finalizationRegistry: FinalizationRegistry<{
target: SemiEventTarget;
weakRef: WeakRef<Callback & {_function?: Callback}>;
eventName: SemiUsedEvent
}>
static initEventListener = () => {
if (!isInited) {
Object.values(SemiUsedEvent).forEach((eventName) => {
[[BaseComponent.windowEventWeakMap, window], [BaseComponent.documentEventWeakMap, document]].forEach(([eventWeakMap, target])=>{
eventWeakMap[eventName] = [];
(target as SemiEventTarget).addEventListener(eventName, (e) => {
eventWeakMap[eventName]?.forEach((ref: WeakRef<Callback & {_function?: Callback}>) => {
const cb = ref.deref();
cb?._function(e);
});
});
});
});
BaseComponent.finalizationRegistry = new FinalizationRegistry(BaseComponent.onEventCallbackGC);
isInited = true;
}

}

static onEventCallbackGC = ({ target, weakRef, eventName }: {
target: SemiEventTarget;
weakRef: WeakRef<Callback & {_function?: Callback}>;
eventName: SemiUsedEvent
}) => {
let eventWeakMap: Record<string, WeakRef<Callback>[]>;
if (target === window) {
eventWeakMap = BaseComponent.windowEventWeakMap;
} else if (target === document) {
eventWeakMap = BaseComponent.documentEventWeakMap;
}
eventWeakMap[eventName] = without(eventWeakMap[eventName] ?? [], weakRef);
}

cache: any;
foundation: any;
componentIsMounted = true;

constructor(props: P) {
super(props);
Expand All @@ -39,6 +97,7 @@ export default class BaseComponent<P extends BaseProps = {}, S = {}> extends Com
}

componentWillUnmount(): void {
this.componentIsMounted = false;
this.foundation && typeof this.foundation.destroy === 'function' && this.foundation.destroy();
this.cache = {};
}
Expand All @@ -56,7 +115,7 @@ export default class BaseComponent<P extends BaseProps = {}, S = {}> extends Com
getProps: () => this.props, // eslint-disable-line
getState: key => this.state[key], // eslint-disable-line
getStates: () => this.state, // eslint-disable-line
setState: (states, cb) => this.setState({ ...states } as S, cb), // eslint-disable-line
setState: (states, cb) => this.setState({...states} as S, cb), // eslint-disable-line
getCache: key => key && this.cache[key], // eslint-disable-line
getCaches: () => this.cache, // eslint-disable-line
setCache: (key, value) => key && (this.cache[key] = value), // eslint-disable-line
Expand Down Expand Up @@ -84,4 +143,27 @@ export default class BaseComponent<P extends BaseProps = {}, S = {}> extends Com
getDataAttr(props?: any) {
return getDataAttr(props);
}

hookedAddEventListener = (target: SemiEventTarget, eventName: SemiUsedEvent, callback: (Callback) & {_function?: Callback}) => {
BaseComponent.initEventListener();
let eventWeakMap: Record<string, WeakRef<(e: Event) => void>[]>;
if (target === window) {
eventWeakMap = BaseComponent.windowEventWeakMap;
} else if (target === document) {
eventWeakMap = BaseComponent.documentEventWeakMap;
}
callback._function = (e)=>{
if (this.componentIsMounted) {
callback(e);
}
};
const weakRef = new WeakRef(callback);
eventWeakMap[eventName]?.push(weakRef);
BaseComponent.finalizationRegistry.register(this, {
target,
weakRef,
eventName
});
}

}
32 changes: 20 additions & 12 deletions packages/semi-ui/_utils/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import { cloneDeepWith, set, get } from 'lodash';
import {cloneDeepWith, set, get} from 'lodash';
import warning from '@douyinfe/semi-foundation/utils/warning';
import { findAll } from '@douyinfe/semi-foundation/utils/getHighlight';
import { isHTMLElement } from '@douyinfe/semi-foundation/utils/dom';
import {findAll} from '@douyinfe/semi-foundation/utils/getHighlight';
import {isHTMLElement} from '@douyinfe/semi-foundation/utils/dom';
import semiGlobal from "./semi-global";

/**
* stop propagation
*
Expand All @@ -22,7 +23,7 @@ export function stopPropagation(e: React.MouseEvent | React.FocusEvent<HTMLEleme

/**
* use in Table, Form, Navigation
*
*
* skip clone function and react element
*/
export function cloneDeep<T>(value: T): T;
Expand Down Expand Up @@ -81,16 +82,16 @@ export function cloneDeep(value: any, customizer?: (value: any) => any) {
* @return {Array<object>}
*/
export const getHighLightTextHTML = ({
sourceString = '',
searchWords = [],
option = { autoEscape: true, caseSensitive: false }
}: GetHighLightTextHTMLProps) => {
const chunks: HighLightTextHTMLChunk[] = findAll({ sourceString, searchWords, ...option });
sourceString = '',
searchWords = [],
option = {autoEscape: true, caseSensitive: false}
}: GetHighLightTextHTMLProps) => {
const chunks: HighLightTextHTMLChunk[] = findAll({sourceString, searchWords, ...option});
const markEle = option.highlightTag || 'mark';
const highlightClassName = option.highlightClassName || '';
const highlightStyle = option.highlightStyle || {};
return chunks.map((chunk: HighLightTextHTMLChunk, index: number) => {
const { end, start, highlight } = chunk;
const {end, start, highlight} = chunk;
const text = sourceString.substr(start, end - start);
if (highlight) {
return React.createElement(
Expand Down Expand Up @@ -120,16 +121,22 @@ export interface RegisterMediaQueryOption {
* @param {object} param param object
* @returns function
*/
export const registerMediaQuery = (media: string, { match, unmatch, callInInit = true }: RegisterMediaQueryOption): () => void => {
export const registerMediaQuery = (media: string, {
match,
unmatch,
callInInit = true
}: RegisterMediaQueryOption): () => void => {
if (typeof window !== 'undefined') {
const mediaQueryList = window.matchMedia(media);

function handlerMediaChange(e: MediaQueryList | MediaQueryListEvent): void {
if (e.matches) {
match && match(e);
} else {
unmatch && unmatch(e);
}
}

callInInit && handlerMediaChange(mediaQueryList);
if (Object.prototype.hasOwnProperty.call(mediaQueryList, 'addEventListener')) {
mediaQueryList.addEventListener('change', handlerMediaChange);
Expand All @@ -140,6 +147,7 @@ export const registerMediaQuery = (media: string, { match, unmatch, callInInit =
}
return () => undefined;
};

export interface GetHighLightTextHTMLProps {
sourceString?: string;
searchWords?: string[];
Expand Down Expand Up @@ -206,7 +214,7 @@ export function getScrollbarWidth() {
}

export function getDefaultPropsFromGlobalConfig(componentName: string, semiDefaultProps: any = {}) {
const getFromGlobalConfig = ()=> semiGlobal?.config?.overrideDefaultProps?.[componentName] || {};
const getFromGlobalConfig = () => semiGlobal?.config?.overrideDefaultProps?.[componentName] || {};
return new Proxy({
...semiDefaultProps,
}, {
Expand Down
1 change: 1 addition & 0 deletions packages/semi-ui/anchor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class Anchor extends BaseComponent<AnchorProps, AnchorState> {
}

componentWillUnmount() {
super.componentWillUnmount();
this.scrollContainer.removeEventListener('scroll', this.handler);
this.scrollContainer.removeEventListener('scroll', this.clickHandler);
}
Expand Down
1 change: 1 addition & 0 deletions packages/semi-ui/anchor/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default class Link extends BaseComponent<LinkProps, {}> {
}

componentWillUnmount() {
super.componentWillUnmount();
this.handleRemoveLink();
}

Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/autoComplete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,7 @@ class AutoComplete<T extends AutoCompleteItems> extends BaseComponent<AutoComple
this.foundation.init();
}

componentWillUnmount() {
this.foundation.destroy();
}


componentDidUpdate(prevProps: AutoCompleteProps<T>, prevState: AutoCompleteState) {
if (!isEqual(this.props.data, prevProps.data)) {
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/avatar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,7 @@ export default class Avatar extends BaseComponent<AvatarProps, AvatarState> {
}
}

componentWillUnmount() {
this.foundation.destroy();
}


onEnter(e: React.MouseEvent) {
this.foundation.handleEnter(e);
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/backtop/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ export default class BackTop extends BaseComponent<BackTopProps, BackTopState> {
this.foundation.init();
}

componentWillUnmount() {
this.foundation.destroy();
}


get adapter(): BackTopAdapter {
return {
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/banner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ export default class Banner extends BaseComponent<BannerProps, BannerState> {
this.foundation.init();
}

componentWillUnmount() {
this.foundation.destroy();
}


remove: React.MouseEventHandler = e => {
e && e.stopPropagation();
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/breadcrumb/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,7 @@ class Breadcrumb extends BaseComponent<BreadcrumbProps, BreadcrumbState> {
this.foundation.init();
}

componentWillUnmount() {
this.foundation.destroy();
}


renderPopoverMore(restItem: Array<React.ReactNode>) {
const { separator } = this.props;
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/breadcrumb/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ export default class BreadcrumbItem extends BaseComponent<BreadcrumbItemProps, B
this.foundation.init();
}

componentWillUnmount() {
this.foundation.destroy();
}


renderIcon = () => {
const iconType = this.props.icon;
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/calendar/dayCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ export default class DayCalendar extends BaseComponent<DayCalendarProps, DayCale
}
}

componentWillUnmount() {
this.foundation.destroy();
}


checkWeekend = (val: Date) => this.foundation.checkWeekend(val);

Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/calendar/dayCol.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ export default class DayCol extends BaseComponent<DayColProps, DayColState> {
this.foundation.initCurrTime();
}

componentWillUnmount() {
this.foundation.destroy();
}


get adapter(): CalendarAdapter<DayColProps, DayColState> {
return {
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/calendar/monthCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,7 @@ export default class monthCalendar extends BaseComponent<MonthCalendarProps, Mon
this.foundation.parseMonthlyEvents(itemLimit);
}

componentWillUnmount() {
this.foundation.destroy();
}


componentDidUpdate(prevProps: MonthCalendarProps, prevState: MonthCalendarState) {
const prevEventKeys = prevState.cachedKeys;
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/calendar/rangeCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,7 @@ export default class RangeCalendar extends BaseComponent<RangeCalendarProps, Ran
}
}

componentWillUnmount() {
this.foundation.destroy();
}


handleClick = (e: React.MouseEvent, val: [Date, number, number, number]) => {
const { onClick } = this.props;
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/calendar/weekCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,7 @@ export default class WeekCalendar extends BaseComponent<WeekCalendarProps, WeekC
}
}

componentWillUnmount() {
this.foundation.destroy();
}



checkWeekend = (val: Date) => this.foundation.checkWeekend(val);
Expand Down
6 changes: 2 additions & 4 deletions packages/semi-ui/carousel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ class Carousel extends BaseComponent<CarouselProps, CarouselState> {
}
}

componentWillUnmount(): void {
this.foundation.destroy();
}


play = (): void => {
this.foundation.setForcePlay(true);
Expand Down Expand Up @@ -305,4 +303,4 @@ class Carousel extends BaseComponent<CarouselProps, CarouselState> {
}
}

export default Carousel;
export default Carousel;
4 changes: 1 addition & 3 deletions packages/semi-ui/cascader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,7 @@ class Cascader extends BaseComponent<CascaderProps, CascaderState> {
this.foundation.init();
}

componentWillUnmount() {
this.foundation.destroy();
}


componentDidUpdate(prevProps: CascaderProps) {
let isOptionsChanged = false;
Expand Down
4 changes: 1 addition & 3 deletions packages/semi-ui/checkbox/checkboxGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ class CheckboxGroup extends BaseComponent<CheckboxGroupProps, CheckboxGroupState
}
}

componentWillUnmount() {
this.foundation.destroy();
}


onChange(evt: CheckboxEvent) {
this.foundation.handleChange(evt);
Expand Down
Loading