mirror of
https://github.com/ant-design/ant-design-mini.git
synced 2024-10-23 08:44:21 +08:00
Detele functional mini (#1204)
* feat: calendar组件去掉hook实现 * feat: demo去hook相关的依赖
This commit is contained in:
parent
204eb27fe9
commit
448bfc323d
@ -1,21 +1,38 @@
|
||||
import dayjs from 'dayjs';
|
||||
import equal from 'fast-deep-equal';
|
||||
import Converter from './js-calendar-converter';
|
||||
import { mountComponent } from '../../../../../src/_util/component';
|
||||
const CollapseContainer = (props) => {
|
||||
var _a, _b, _c;
|
||||
const time = dayjs((_a = props.cell) === null || _a === void 0 ? void 0 : _a.time);
|
||||
const vs = Converter.solar2lunar(time.get('year'), time.get('month') + 1, time.get('date'));
|
||||
if (vs === -1) {
|
||||
return {
|
||||
cnday: '',
|
||||
};
|
||||
}
|
||||
return {
|
||||
cnday: vs.lunarFestival || vs.festival || vs.IDayCn,
|
||||
festival: !!vs.festival || !!vs.lunarFestival,
|
||||
unset: ((_b = props.cell) === null || _b === void 0 ? void 0 : _b.isSelectedBegin) || ((_c = props.cell) === null || _c === void 0 ? void 0 : _c.isSelectedEnd),
|
||||
};
|
||||
};
|
||||
mountComponent(CollapseContainer, {
|
||||
import { Component, getValueFromProps } from '../../../../../src/_util/simply';
|
||||
Component({
|
||||
cell: null,
|
||||
}, {
|
||||
updateData() {
|
||||
const cell = getValueFromProps(this, 'cell');
|
||||
const time = dayjs(cell === null || cell === void 0 ? void 0 : cell.time);
|
||||
const vs = Converter.solar2lunar(time.get('year'), time.get('month') + 1, time.get('date'));
|
||||
if (vs === -1) {
|
||||
this.setData({
|
||||
cnday: '',
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setData({
|
||||
cnday: vs.lunarFestival || vs.festival || vs.IDayCn,
|
||||
festival: !!vs.festival || !!vs.lunarFestival,
|
||||
unset: (cell === null || cell === void 0 ? void 0 : cell.isSelectedBegin) || (cell === null || cell === void 0 ? void 0 : cell.isSelectedEnd),
|
||||
});
|
||||
},
|
||||
}, {
|
||||
cnday: '',
|
||||
festival: '',
|
||||
unset: '',
|
||||
}, null, {
|
||||
onInit() {
|
||||
this.updateData();
|
||||
},
|
||||
didUpdate(prevProps) {
|
||||
const cell = getValueFromProps(this, 'cell');
|
||||
if (!equal(prevProps.cell, cell)) {
|
||||
this.updateData();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -1,19 +1,30 @@
|
||||
import { useEvent, useState } from 'functional-mini/component';
|
||||
import { mountComponent } from '../../../../src/_util/component';
|
||||
const CollapseContainer = (props) => {
|
||||
var _a;
|
||||
const [collapse, setCollapse] = useState((_a = props.defaultCollapse) !== null && _a !== void 0 ? _a : true);
|
||||
useEvent('handleToggle', () => {
|
||||
setCollapse((v) => !v);
|
||||
});
|
||||
return {
|
||||
collapse,
|
||||
internalHide: props.hide,
|
||||
containerTitle: props.title,
|
||||
};
|
||||
};
|
||||
mountComponent(CollapseContainer, {
|
||||
import { Component, getValueFromProps } from '../../../../src/_util/simply';
|
||||
Component({
|
||||
hide: false,
|
||||
defaultCollapse: null,
|
||||
title: '',
|
||||
}, {
|
||||
handleToggle() {
|
||||
const { collapse } = this.data;
|
||||
this.setData({
|
||||
collapse: !collapse,
|
||||
});
|
||||
},
|
||||
}, {
|
||||
collapse: true,
|
||||
internalHide: false,
|
||||
containerTitle: '',
|
||||
}, null, {
|
||||
onInit() {
|
||||
const [defaultCollapse, hide, title] = getValueFromProps(this, [
|
||||
'defaultCollapse',
|
||||
'hide',
|
||||
'title',
|
||||
]);
|
||||
this.setData({
|
||||
collapse: defaultCollapse !== null && defaultCollapse !== void 0 ? defaultCollapse : true,
|
||||
internalHide: hide,
|
||||
containerTitle: title,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { alipayComponent, wechatComponent } from 'functional-mini/component';
|
||||
|
||||
function removeNullProps(props) {
|
||||
const newProps = {};
|
||||
for (const key in props) {
|
||||
if (props[key] !== null) {
|
||||
newProps[key] = props[key];
|
||||
}
|
||||
}
|
||||
return newProps;
|
||||
}
|
||||
|
||||
export function mountComponent<T>(
|
||||
Hooks: (props: T) => unknown,
|
||||
defaultProps: T
|
||||
) {
|
||||
|
||||
Component(
|
||||
alipayComponent(Hooks, removeNullProps(mergeDefaultProps(defaultProps)))
|
||||
);
|
||||
}
|
||||
|
||||
function mergeDefaultProps(defaultProps: Record<string, any> = {}) {
|
||||
return {
|
||||
...defaultProps,
|
||||
};
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
import { useComponent } from 'functional-mini/component';
|
||||
import fmtEvent from '../fmtEvent';
|
||||
import { useEvent } from './useEvent';
|
||||
|
||||
export function useComponentEvent<T>(props: T) {
|
||||
const component = useComponent();
|
||||
const triggerEvent = useEvent(
|
||||
(eventName: string, value: unknown, e?: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](value, fmtEvent(props, e));
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
const triggerEventValues = useEvent(
|
||||
(eventName: string, values: any[], e?: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](...values, fmtEvent(props, e));
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
const triggerEventOnly = useEvent((eventName: string, e?: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](fmtEvent(props, e));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const alipayForwardCatchEvent = useEvent((eventName: string, e: any) => {
|
||||
// 首字母大写,然后加上 catch
|
||||
|
||||
const alipayCallbackName =
|
||||
'catch' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](fmtEvent(props, e));
|
||||
}
|
||||
});
|
||||
|
||||
const alipayForwardEvent = useEvent((eventName: string, e: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](fmtEvent(props, e));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
triggerEvent,
|
||||
triggerEventValues,
|
||||
triggerEventOnly,
|
||||
// 转发 catch 事件
|
||||
alipayForwardCatchEvent,
|
||||
// 转发事件
|
||||
alipayForwardEvent,
|
||||
};
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useEvent.ts
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import * as React from 'functional-mini/compat';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function useEvent<T extends Function>(callback: T): T {
|
||||
const fnRef = React.useRef<any>();
|
||||
fnRef.current = callback;
|
||||
|
||||
const memoFn = React.useCallback<T>(
|
||||
((...args: any) => fnRef.current?.(...args)) as any,
|
||||
[]
|
||||
);
|
||||
|
||||
return memoFn;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { useEvent } from 'functional-mini/component';
|
||||
import { platform } from '../platform';
|
||||
|
||||
export type EventHandler<T> = (value: T, e: any) => void;
|
||||
|
||||
export const useHandleCustomEvent = <T>(
|
||||
eventName: string,
|
||||
handler: EventHandler<T>
|
||||
) => {
|
||||
useEvent(
|
||||
eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(eventOrValue: any, alipayEvent?: any) => {
|
||||
if (platform() === 'alipay') {
|
||||
return handler(eventOrValue, alipayEvent);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export type MultipleValueEventHandler<T> = (...args: any[]) => void;
|
||||
|
||||
export const useMultipleValueHandleCustomEvent = <T extends any[]>(
|
||||
eventName: string,
|
||||
handler: MultipleValueEventHandler<T>
|
||||
) => {
|
||||
useEvent(
|
||||
eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(...args: any[]) => {
|
||||
if (platform() === 'alipay') {
|
||||
return handler(...args);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export type EventOnlyHandler = (e: any) => void;
|
||||
|
||||
export const useHandleCustomEventOnly = (
|
||||
eventName: string,
|
||||
handler: EventOnlyHandler
|
||||
) => {
|
||||
useEvent(
|
||||
eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(event) => {
|
||||
if (platform() === 'alipay') {
|
||||
return handler(event);
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
import { useComponent } from 'functional-mini/component';
|
||||
import { getInstanceBoundingClientRect } from '../jsapi/get-instance-bounding-client-rect';
|
||||
|
||||
export const useInstanceBoundingClientRect = () => {
|
||||
const instance = useComponent();
|
||||
function getInstance() {
|
||||
if (instance.$id) {
|
||||
return my;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
async function getBoundingClientRectWithId(prefix: string) {
|
||||
return await getInstanceBoundingClientRect(
|
||||
getInstance(),
|
||||
`${prefix}${instance.$id ? `-${instance.$id}` : ''}`
|
||||
);
|
||||
}
|
||||
async function getBoundingClientRect(query: string) {
|
||||
return await getInstanceBoundingClientRect(getInstance(), query);
|
||||
}
|
||||
|
||||
async function getBoundingClientRectWithBuilder(
|
||||
builder: (id: string) => string
|
||||
) {
|
||||
return await getInstanceBoundingClientRect(
|
||||
getInstance(),
|
||||
builder(instance.$id ? `-${instance.$id}` : '')
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
getBoundingClientRect,
|
||||
getBoundingClientRectWithId,
|
||||
getBoundingClientRectWithBuilder,
|
||||
};
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useLayoutEffect.ts
|
||||
*/
|
||||
|
||||
import * as React from 'functional-mini/compat';
|
||||
|
||||
/**
|
||||
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
||||
*/
|
||||
const useInternalLayoutEffect = React.useEffect;
|
||||
|
||||
const useLayoutEffect = (callback: (mount: boolean) => void, deps?: any) => {
|
||||
const firstMountRef = React.useRef(true);
|
||||
|
||||
useInternalLayoutEffect(() => {
|
||||
return callback(firstMountRef.current);
|
||||
}, deps);
|
||||
|
||||
// We tell react that first mount has passed
|
||||
useInternalLayoutEffect(() => {
|
||||
firstMountRef.current = false;
|
||||
return () => {
|
||||
firstMountRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
|
||||
export const useComponentUpdateEffect: typeof React.useEffect = (
|
||||
callback,
|
||||
deps
|
||||
) => {
|
||||
useLayoutEffect((firstMount) => {
|
||||
if (!firstMount) {
|
||||
return callback();
|
||||
}
|
||||
}, deps);
|
||||
};
|
||||
|
||||
export default useLayoutEffect;
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useMergedState.ts
|
||||
*/
|
||||
import { useEvent } from './useEvent';
|
||||
import { useComponentUpdateEffect } from './useLayoutEffect';
|
||||
import { useSafeState as useState } from './useState';
|
||||
import { supportUndefinedProperty } from '../platform';
|
||||
|
||||
type Updater<T> = (
|
||||
updater: T | ((origin: T) => T),
|
||||
ignoreDestroy?: boolean
|
||||
) => void;
|
||||
|
||||
/** We only think `undefined` is empty */
|
||||
export function hasValue(value: any) {
|
||||
if (supportUndefinedProperty()) {
|
||||
return value !== undefined;
|
||||
}
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `useState` but will use props value if provided.
|
||||
* Note that internal use rc-util `useState` hook.
|
||||
*/
|
||||
export function useMergedState<T, R = T>(
|
||||
defaultStateValue: T | (() => T),
|
||||
option?: {
|
||||
defaultValue?: T | (() => T);
|
||||
value?: T;
|
||||
onChange?: (value: T, prevValue: T) => void;
|
||||
postState?: (value: T) => T;
|
||||
}
|
||||
): [R, Updater<T>] {
|
||||
const { defaultValue, value, onChange, postState } = option || {};
|
||||
|
||||
// ======================= Init =======================
|
||||
const [innerValue, setInnerValue] = useState<T>(() => {
|
||||
if (hasValue(value)) {
|
||||
return value;
|
||||
} else if (hasValue(defaultValue)) {
|
||||
return typeof defaultValue === 'function'
|
||||
? (defaultValue as any)()
|
||||
: defaultValue;
|
||||
} else {
|
||||
return typeof defaultStateValue === 'function'
|
||||
? (defaultStateValue as any)()
|
||||
: defaultStateValue;
|
||||
}
|
||||
});
|
||||
|
||||
const mergedValue = hasValue(value) ? value : innerValue;
|
||||
const postMergedValue = postState ? postState(mergedValue) : mergedValue;
|
||||
|
||||
// ====================== Change ======================
|
||||
const onChangeFn = useEvent(onChange);
|
||||
|
||||
const [prevValue, setPrevValue] = useState<[T]>([mergedValue]);
|
||||
|
||||
useComponentUpdateEffect(() => {
|
||||
const prev = prevValue[0];
|
||||
if (innerValue !== prev) {
|
||||
onChangeFn(innerValue, prev);
|
||||
}
|
||||
}, [prevValue]);
|
||||
|
||||
// Sync value back to `undefined` when it from control to un-control
|
||||
useComponentUpdateEffect(() => {
|
||||
if (!hasValue(value)) {
|
||||
setInnerValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
// ====================== Update ======================
|
||||
const triggerChange: Updater<T> = useEvent((updater, ignoreDestroy) => {
|
||||
setInnerValue(updater, ignoreDestroy);
|
||||
setPrevValue([mergedValue], ignoreDestroy);
|
||||
});
|
||||
|
||||
return [postMergedValue as unknown as R, triggerChange];
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
import { useEvent } from './useEvent';
|
||||
import { useComponentUpdateEffect } from './useLayoutEffect';
|
||||
import { hasValue } from './useMergedState';
|
||||
import { useSafeState as useState } from './useState';
|
||||
|
||||
type Updater<T> = (
|
||||
updater: T | ((old: T) => T),
|
||||
ignoreDestroy?: boolean
|
||||
) => void;
|
||||
|
||||
export function useMixState<T, R = T, O = undefined>(
|
||||
defaultStateValue: T | (() => T),
|
||||
option?: {
|
||||
defaultValue?: T | (() => T);
|
||||
value?: T;
|
||||
postState?: (
|
||||
value: T,
|
||||
option?: O
|
||||
) => { valid: true; value: T } | { valid: false };
|
||||
}
|
||||
): [
|
||||
R,
|
||||
{
|
||||
isControlled: boolean;
|
||||
triggerUpdater: (value: (old: T) => T, option?: O) => void;
|
||||
update(
|
||||
value: T,
|
||||
option?: O
|
||||
): { changed: true; newValue: T } | { changed: false };
|
||||
}
|
||||
] {
|
||||
const {
|
||||
defaultValue,
|
||||
value,
|
||||
postState = (v) => ({ valid: true, value: v }),
|
||||
} = option || {};
|
||||
|
||||
// ======================= Init =======================
|
||||
const [innerValue, setInnerValue] = useState<T>(() => {
|
||||
let v;
|
||||
if (hasValue(value)) {
|
||||
v = value;
|
||||
} else if (hasValue(defaultValue)) {
|
||||
v =
|
||||
typeof defaultValue === 'function'
|
||||
? (defaultValue as any)()
|
||||
: defaultValue;
|
||||
} else {
|
||||
v =
|
||||
typeof defaultStateValue === 'function'
|
||||
? (defaultStateValue as any)()
|
||||
: defaultStateValue;
|
||||
}
|
||||
const state = postState(v);
|
||||
if (state.valid) {
|
||||
return state.value;
|
||||
}
|
||||
});
|
||||
|
||||
const state = postState(value);
|
||||
const merge = hasValue(value) && state.valid ? state.value : innerValue;
|
||||
|
||||
useComponentUpdateEffect(() => {
|
||||
const state = postState(value);
|
||||
if (state.valid) {
|
||||
setInnerValue(state.value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const isControlled = hasValue(value);
|
||||
const triggerChange: Updater<T> = useEvent((newState, ignoreDestroy) => {
|
||||
setInnerValue(newState, ignoreDestroy);
|
||||
});
|
||||
|
||||
const triggerUpdate = useEvent((value, option) => {
|
||||
const state = postState(value, option);
|
||||
if (state.valid && state.value !== innerValue) {
|
||||
triggerChange(state.value);
|
||||
return { changed: true, newValue: state.value };
|
||||
}
|
||||
return { changed: false };
|
||||
});
|
||||
|
||||
const triggerUpdater: (value: (old: T) => T, option?: O) => void = useEvent(
|
||||
(getValue, option) => {
|
||||
if (isControlled) {
|
||||
getValue(merge);
|
||||
} else {
|
||||
triggerChange((old: T): T => {
|
||||
const newValue = getValue(old);
|
||||
const state = postState(newValue, option);
|
||||
if (state.valid && state.value !== innerValue) {
|
||||
return state.value;
|
||||
}
|
||||
return old;
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return [
|
||||
merge as unknown as R,
|
||||
{
|
||||
isControlled,
|
||||
update: triggerUpdate as any,
|
||||
triggerUpdater,
|
||||
},
|
||||
];
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
import { useComponent, useEffect } from 'functional-mini/component';
|
||||
|
||||
export const triggerRefEvent = () => {
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useState.ts
|
||||
*/
|
||||
|
||||
import * as React from 'functional-mini/compat';
|
||||
|
||||
type Updater<T> = T | ((prevValue: T) => T);
|
||||
|
||||
export type SetState<T> = (
|
||||
nextValue: Updater<T>,
|
||||
/**
|
||||
* Will not update state when destroyed.
|
||||
* Developer should make sure this is safe to ignore.
|
||||
*/
|
||||
ignoreDestroy?: boolean
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Same as React.useState but `setState` accept `ignoreDestroy` param to not to setState after destroyed.
|
||||
* We do not make this auto is to avoid real memory leak.
|
||||
* Developer should confirm it's safe to ignore themselves.
|
||||
*/
|
||||
export function useSafeState<T>(
|
||||
defaultValue?: T | (() => T)
|
||||
): [T, SetState<T>] {
|
||||
const destroyRef = React.useRef(false);
|
||||
const [value, setValue] = React.useState(defaultValue);
|
||||
|
||||
React.useEffect(() => {
|
||||
destroyRef.current = false;
|
||||
|
||||
return () => {
|
||||
destroyRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
function safeSetState(updater: Updater<T>, ignoreDestroy?: boolean) {
|
||||
if (ignoreDestroy && destroyRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setValue(updater);
|
||||
}
|
||||
|
||||
return [value, safeSetState];
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
export function triggerComponentEvent(instance, propsName, event) {
|
||||
|
||||
if (instance.props[propsName]) {
|
||||
instance.props[propsName](event);
|
||||
}
|
||||
}
|
@ -1,21 +1,41 @@
|
||||
import dayjs from 'dayjs';
|
||||
import equal from 'fast-deep-equal';
|
||||
import Converter from './js-calendar-converter';
|
||||
import { mountComponent } from '../../../../../src/_util/component';
|
||||
const CollapseContainer = (props) => {
|
||||
var _a, _b, _c;
|
||||
const time = dayjs((_a = props.cell) === null || _a === void 0 ? void 0 : _a.time);
|
||||
const vs = Converter.solar2lunar(time.get('year'), time.get('month') + 1, time.get('date'));
|
||||
if (vs === -1) {
|
||||
return {
|
||||
cnday: '',
|
||||
};
|
||||
}
|
||||
return {
|
||||
cnday: vs.lunarFestival || vs.festival || vs.IDayCn,
|
||||
festival: !!vs.festival || !!vs.lunarFestival,
|
||||
unset: ((_b = props.cell) === null || _b === void 0 ? void 0 : _b.isSelectedBegin) || ((_c = props.cell) === null || _c === void 0 ? void 0 : _c.isSelectedEnd),
|
||||
};
|
||||
};
|
||||
mountComponent(CollapseContainer, {
|
||||
import { Component, getValueFromProps } from '../../../../../src/_util/simply';
|
||||
Component({
|
||||
cell: null,
|
||||
}, {
|
||||
updateData() {
|
||||
const cell = getValueFromProps(this, 'cell');
|
||||
const time = dayjs(cell === null || cell === void 0 ? void 0 : cell.time);
|
||||
const vs = Converter.solar2lunar(time.get('year'), time.get('month') + 1, time.get('date'));
|
||||
if (vs === -1) {
|
||||
this.setData({
|
||||
cnday: '',
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setData({
|
||||
cnday: vs.lunarFestival || vs.festival || vs.IDayCn,
|
||||
festival: !!vs.festival || !!vs.lunarFestival,
|
||||
unset: (cell === null || cell === void 0 ? void 0 : cell.isSelectedBegin) || (cell === null || cell === void 0 ? void 0 : cell.isSelectedEnd),
|
||||
});
|
||||
},
|
||||
}, {
|
||||
cnday: '',
|
||||
festival: '',
|
||||
unset: '',
|
||||
}, null, {
|
||||
attached() {
|
||||
this.updateData();
|
||||
},
|
||||
observers: {
|
||||
'**': function (data) {
|
||||
const prevData = this._prevData || this.data;
|
||||
this._prevData = { ...data };
|
||||
if (!equal(prevData.cell, data.cell)) {
|
||||
this.updateData();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,19 +1,30 @@
|
||||
import { useEvent, useState } from 'functional-mini/component';
|
||||
import { mountComponent } from '../../../../src/_util/component';
|
||||
const CollapseContainer = (props) => {
|
||||
var _a;
|
||||
const [collapse, setCollapse] = useState((_a = props.defaultCollapse) !== null && _a !== void 0 ? _a : true);
|
||||
useEvent('handleToggle', () => {
|
||||
setCollapse((v) => !v);
|
||||
});
|
||||
return {
|
||||
collapse,
|
||||
internalHide: props.hide,
|
||||
containerTitle: props.title,
|
||||
};
|
||||
};
|
||||
mountComponent(CollapseContainer, {
|
||||
import { Component, getValueFromProps } from '../../../../src/_util/simply';
|
||||
Component({
|
||||
hide: false,
|
||||
defaultCollapse: null,
|
||||
title: '',
|
||||
}, {
|
||||
handleToggle() {
|
||||
const { collapse } = this.data;
|
||||
this.setData({
|
||||
collapse: !collapse,
|
||||
});
|
||||
},
|
||||
}, {
|
||||
collapse: true,
|
||||
internalHide: false,
|
||||
containerTitle: '',
|
||||
}, null, {
|
||||
attached() {
|
||||
const [defaultCollapse, hide, title] = getValueFromProps(this, [
|
||||
'defaultCollapse',
|
||||
'hide',
|
||||
'title',
|
||||
]);
|
||||
this.setData({
|
||||
collapse: defaultCollapse !== null && defaultCollapse !== void 0 ? defaultCollapse : true,
|
||||
internalHide: hide,
|
||||
containerTitle: title,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -4,7 +4,6 @@
|
||||
"async-validator": "^4.0.7",
|
||||
"dayjs": "^1.11.10",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"functional-mini": "^0.17.0",
|
||||
"tslib": "2.5.0"
|
||||
},
|
||||
"repository": "git@github.com:ant-design/ant-design-mini.git"
|
||||
|
@ -1,34 +0,0 @@
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
import { wechatComponent } from 'functional-mini/component';
|
||||
function removeNullProps(props) {
|
||||
var newProps = {};
|
||||
for (var key in props) {
|
||||
if (props[key] !== null) {
|
||||
newProps[key] = props[key];
|
||||
}
|
||||
}
|
||||
return newProps;
|
||||
}
|
||||
export function mountComponent(Hooks, defaultProps) {
|
||||
Component(wechatComponent(Hooks, mergeDefaultProps(defaultProps), {
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
multipleSlots: true,
|
||||
virtualHost: true,
|
||||
},
|
||||
}));
|
||||
}
|
||||
function mergeDefaultProps(defaultProps) {
|
||||
if (defaultProps === void 0) { defaultProps = {}; }
|
||||
return __assign({ className: '', style: '' }, defaultProps);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { useComponent } from 'functional-mini/component';
|
||||
import { useEvent } from './useEvent';
|
||||
export function useComponentEvent(props) {
|
||||
var component = useComponent();
|
||||
var triggerEvent = useEvent(function (eventName, value, e) {
|
||||
// 首字母大写,然后加上 on
|
||||
component.triggerEvent(eventName.toLocaleLowerCase(), value);
|
||||
});
|
||||
var triggerEventValues = useEvent(function (eventName, values, e) {
|
||||
// 首字母大写,然后加上 on
|
||||
component.triggerEvent(eventName.toLocaleLowerCase(), values);
|
||||
});
|
||||
var triggerEventOnly = useEvent(function (eventName, e) {
|
||||
// 首字母大写,然后加上 on
|
||||
component.triggerEvent(eventName.toLocaleLowerCase());
|
||||
});
|
||||
var alipayForwardCatchEvent = useEvent(function (eventName, e) {
|
||||
// 首字母大写,然后加上 catch
|
||||
});
|
||||
var alipayForwardEvent = useEvent(function (eventName, e) {
|
||||
// 首字母大写,然后加上 on
|
||||
});
|
||||
return {
|
||||
triggerEvent: triggerEvent,
|
||||
triggerEventValues: triggerEventValues,
|
||||
triggerEventOnly: triggerEventOnly,
|
||||
// 转发 catch 事件
|
||||
alipayForwardCatchEvent: alipayForwardCatchEvent,
|
||||
// 转发事件
|
||||
alipayForwardEvent: alipayForwardEvent,
|
||||
};
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
||||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
||||
if (ar || !(i in from)) {
|
||||
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
||||
ar[i] = from[i];
|
||||
}
|
||||
}
|
||||
return to.concat(ar || Array.prototype.slice.call(from));
|
||||
};
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useEvent.ts
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import * as React from 'functional-mini/compat';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function useEvent(callback) {
|
||||
var fnRef = React.useRef();
|
||||
fnRef.current = callback;
|
||||
var memoFn = React.useCallback((function () {
|
||||
var _a;
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return (_a = fnRef.current) === null || _a === void 0 ? void 0 : _a.call.apply(_a, __spreadArray([fnRef], args, false));
|
||||
}), []);
|
||||
return memoFn;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import { useEvent } from 'functional-mini/component';
|
||||
export var useHandleCustomEvent = function (eventName, handler) {
|
||||
useEvent(eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function (eventOrValue, alipayEvent) {
|
||||
return handler(eventOrValue.detail, eventOrValue);
|
||||
});
|
||||
};
|
||||
export var useMultipleValueHandleCustomEvent = function (eventName, handler) {
|
||||
useEvent(eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
var firstArgs = args[0];
|
||||
if (Array.isArray(firstArgs.detail)) {
|
||||
var wechatArgs = firstArgs.detail.concat(firstArgs);
|
||||
return handler.apply(void 0, wechatArgs);
|
||||
}
|
||||
else {
|
||||
return handler([firstArgs.detail, firstArgs]);
|
||||
}
|
||||
});
|
||||
};
|
||||
export var useHandleCustomEventOnly = function (eventName, handler) {
|
||||
useEvent(eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function (event) {
|
||||
return handler(event);
|
||||
});
|
||||
};
|
@ -1,82 +0,0 @@
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
import { useComponent } from 'functional-mini/component';
|
||||
import { getInstanceBoundingClientRect } from '../jsapi/get-instance-bounding-client-rect';
|
||||
export var useInstanceBoundingClientRect = function () {
|
||||
var instance = useComponent();
|
||||
function getInstance() {
|
||||
if (instance.$id) {
|
||||
return my;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
function getBoundingClientRectWithId(prefix) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(getInstance(), "".concat(prefix).concat(instance.$id ? "-".concat(instance.$id) : ''))];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function getBoundingClientRect(query) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(getInstance(), query)];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function getBoundingClientRectWithBuilder(builder) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(getInstance(), builder(instance.$id ? "-".concat(instance.$id) : ''))];
|
||||
case 1: return [2 /*return*/, _a.sent()];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return {
|
||||
getBoundingClientRect: getBoundingClientRect,
|
||||
getBoundingClientRectWithId: getBoundingClientRectWithId,
|
||||
getBoundingClientRectWithBuilder: getBoundingClientRectWithBuilder,
|
||||
};
|
||||
};
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useLayoutEffect.ts
|
||||
*/
|
||||
import * as React from 'functional-mini/compat';
|
||||
/**
|
||||
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
||||
*/
|
||||
var useInternalLayoutEffect = React.useEffect;
|
||||
var useLayoutEffect = function (callback, deps) {
|
||||
var firstMountRef = React.useRef(true);
|
||||
useInternalLayoutEffect(function () {
|
||||
return callback(firstMountRef.current);
|
||||
}, deps);
|
||||
// We tell react that first mount has passed
|
||||
useInternalLayoutEffect(function () {
|
||||
firstMountRef.current = false;
|
||||
return function () {
|
||||
firstMountRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
export var useComponentUpdateEffect = function (callback, deps) {
|
||||
useLayoutEffect(function (firstMount) {
|
||||
if (!firstMount) {
|
||||
return callback();
|
||||
}
|
||||
}, deps);
|
||||
};
|
||||
export default useLayoutEffect;
|
@ -1,60 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useMergedState.ts
|
||||
*/
|
||||
import { useEvent } from './useEvent';
|
||||
import { useComponentUpdateEffect } from './useLayoutEffect';
|
||||
import { useSafeState as useState } from './useState';
|
||||
import { supportUndefinedProperty } from '../platform';
|
||||
/** We only think `undefined` is empty */
|
||||
export function hasValue(value) {
|
||||
if (supportUndefinedProperty()) {
|
||||
return value !== undefined;
|
||||
}
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
/**
|
||||
* Similar to `useState` but will use props value if provided.
|
||||
* Note that internal use rc-util `useState` hook.
|
||||
*/
|
||||
export function useMergedState(defaultStateValue, option) {
|
||||
var _a = option || {}, defaultValue = _a.defaultValue, value = _a.value, onChange = _a.onChange, postState = _a.postState;
|
||||
// ======================= Init =======================
|
||||
var _b = useState(function () {
|
||||
if (hasValue(value)) {
|
||||
return value;
|
||||
}
|
||||
else if (hasValue(defaultValue)) {
|
||||
return typeof defaultValue === 'function'
|
||||
? defaultValue()
|
||||
: defaultValue;
|
||||
}
|
||||
else {
|
||||
return typeof defaultStateValue === 'function'
|
||||
? defaultStateValue()
|
||||
: defaultStateValue;
|
||||
}
|
||||
}), innerValue = _b[0], setInnerValue = _b[1];
|
||||
var mergedValue = hasValue(value) ? value : innerValue;
|
||||
var postMergedValue = postState ? postState(mergedValue) : mergedValue;
|
||||
// ====================== Change ======================
|
||||
var onChangeFn = useEvent(onChange);
|
||||
var _c = useState([mergedValue]), prevValue = _c[0], setPrevValue = _c[1];
|
||||
useComponentUpdateEffect(function () {
|
||||
var prev = prevValue[0];
|
||||
if (innerValue !== prev) {
|
||||
onChangeFn(innerValue, prev);
|
||||
}
|
||||
}, [prevValue]);
|
||||
// Sync value back to `undefined` when it from control to un-control
|
||||
useComponentUpdateEffect(function () {
|
||||
if (!hasValue(value)) {
|
||||
setInnerValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
// ====================== Update ======================
|
||||
var triggerChange = useEvent(function (updater, ignoreDestroy) {
|
||||
setInnerValue(updater, ignoreDestroy);
|
||||
setPrevValue([mergedValue], ignoreDestroy);
|
||||
});
|
||||
return [postMergedValue, triggerChange];
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import { useEvent } from './useEvent';
|
||||
import { useComponentUpdateEffect } from './useLayoutEffect';
|
||||
import { hasValue } from './useMergedState';
|
||||
import { useSafeState as useState } from './useState';
|
||||
export function useMixState(defaultStateValue, option) {
|
||||
var _a = option || {}, defaultValue = _a.defaultValue, value = _a.value, _b = _a.postState, postState = _b === void 0 ? function (v) { return ({ valid: true, value: v }); } : _b;
|
||||
// ======================= Init =======================
|
||||
var _c = useState(function () {
|
||||
var v;
|
||||
if (hasValue(value)) {
|
||||
v = value;
|
||||
}
|
||||
else if (hasValue(defaultValue)) {
|
||||
v =
|
||||
typeof defaultValue === 'function'
|
||||
? defaultValue()
|
||||
: defaultValue;
|
||||
}
|
||||
else {
|
||||
v =
|
||||
typeof defaultStateValue === 'function'
|
||||
? defaultStateValue()
|
||||
: defaultStateValue;
|
||||
}
|
||||
var state = postState(v);
|
||||
if (state.valid) {
|
||||
return state.value;
|
||||
}
|
||||
}), innerValue = _c[0], setInnerValue = _c[1];
|
||||
var state = postState(value);
|
||||
var merge = hasValue(value) && state.valid ? state.value : innerValue;
|
||||
useComponentUpdateEffect(function () {
|
||||
var state = postState(value);
|
||||
if (state.valid) {
|
||||
setInnerValue(state.value);
|
||||
}
|
||||
}, [value]);
|
||||
var isControlled = hasValue(value);
|
||||
var triggerChange = useEvent(function (newState, ignoreDestroy) {
|
||||
setInnerValue(newState, ignoreDestroy);
|
||||
});
|
||||
var triggerUpdate = useEvent(function (value, option) {
|
||||
var state = postState(value, option);
|
||||
if (state.valid && state.value !== innerValue) {
|
||||
triggerChange(state.value);
|
||||
return { changed: true, newValue: state.value };
|
||||
}
|
||||
return { changed: false };
|
||||
});
|
||||
var triggerUpdater = useEvent(function (getValue, option) {
|
||||
if (isControlled) {
|
||||
getValue(merge);
|
||||
}
|
||||
else {
|
||||
triggerChange(function (old) {
|
||||
var newValue = getValue(old);
|
||||
var state = postState(newValue, option);
|
||||
if (state.valid && state.value !== innerValue) {
|
||||
return state.value;
|
||||
}
|
||||
return old;
|
||||
});
|
||||
}
|
||||
});
|
||||
return [
|
||||
merge,
|
||||
{
|
||||
isControlled: isControlled,
|
||||
update: triggerUpdate,
|
||||
triggerUpdater: triggerUpdater,
|
||||
},
|
||||
];
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { useComponent, useEffect } from 'functional-mini/component';
|
||||
export var triggerRefEvent = function () {
|
||||
var component = useComponent();
|
||||
useEffect(function () {
|
||||
component.triggerEvent('ref', component);
|
||||
}, []);
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useState.ts
|
||||
*/
|
||||
import * as React from 'functional-mini/compat';
|
||||
/**
|
||||
* Same as React.useState but `setState` accept `ignoreDestroy` param to not to setState after destroyed.
|
||||
* We do not make this auto is to avoid real memory leak.
|
||||
* Developer should confirm it's safe to ignore themselves.
|
||||
*/
|
||||
export function useSafeState(defaultValue) {
|
||||
var destroyRef = React.useRef(false);
|
||||
var _a = React.useState(defaultValue), value = _a[0], setValue = _a[1];
|
||||
React.useEffect(function () {
|
||||
destroyRef.current = false;
|
||||
return function () {
|
||||
destroyRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
function safeSetState(updater, ignoreDestroy) {
|
||||
if (ignoreDestroy && destroyRef.current) {
|
||||
return;
|
||||
}
|
||||
setValue(updater);
|
||||
}
|
||||
return [value, safeSetState];
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export function triggerComponentEvent(instance, propsName, event) {
|
||||
instance.triggerEvent(propsName, event.detail);
|
||||
}
|
@ -1,31 +1,69 @@
|
||||
import dayjs from 'dayjs';
|
||||
import equal from 'fast-deep-equal';
|
||||
import Converter from './js-calendar-converter';
|
||||
import { mountComponent } from '../../../../../src/_util/component';
|
||||
import { Component, getValueFromProps } from '../../../../../src/_util/simply';
|
||||
|
||||
interface Props {
|
||||
cell: any;
|
||||
}
|
||||
|
||||
const CollapseContainer = (props: Props) => {
|
||||
const time = dayjs(props.cell?.time);
|
||||
const vs = Converter.solar2lunar(
|
||||
time.get('year'),
|
||||
time.get('month') + 1,
|
||||
time.get('date')
|
||||
);
|
||||
if (vs === -1) {
|
||||
return {
|
||||
cnday: '',
|
||||
};
|
||||
Component(
|
||||
{
|
||||
cell: null,
|
||||
} as Props,
|
||||
{
|
||||
updateData() {
|
||||
const cell = getValueFromProps(this, 'cell');
|
||||
const time = dayjs(cell?.time);
|
||||
const vs = Converter.solar2lunar(
|
||||
time.get('year'),
|
||||
time.get('month') + 1,
|
||||
time.get('date')
|
||||
);
|
||||
if (vs === -1) {
|
||||
this.setData({
|
||||
cnday: '',
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setData({
|
||||
cnday: vs.lunarFestival || vs.festival || vs.IDayCn,
|
||||
festival: !!vs.festival || !!vs.lunarFestival,
|
||||
unset: cell?.isSelectedBegin || cell?.isSelectedEnd,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
cnday: '',
|
||||
festival: '',
|
||||
unset: '',
|
||||
},
|
||||
null,
|
||||
{
|
||||
/// #if ALIPAY
|
||||
onInit() {
|
||||
this.updateData();
|
||||
},
|
||||
didUpdate(prevProps) {
|
||||
const cell = getValueFromProps(this, 'cell');
|
||||
if (!equal(prevProps.cell, cell)) {
|
||||
this.updateData();
|
||||
}
|
||||
},
|
||||
/// #endif
|
||||
/// #if WECHAT
|
||||
attached() {
|
||||
this.updateData();
|
||||
},
|
||||
observers: {
|
||||
'**': function (data) {
|
||||
const prevData = this._prevData || this.data;
|
||||
this._prevData = { ...data };
|
||||
if (!equal(prevData.cell, data.cell)) {
|
||||
this.updateData();
|
||||
}
|
||||
},
|
||||
},
|
||||
/// #endif
|
||||
}
|
||||
|
||||
return {
|
||||
cnday: vs.lunarFestival || vs.festival || vs.IDayCn,
|
||||
festival: !!vs.festival || !!vs.lunarFestival,
|
||||
unset: props.cell?.isSelectedBegin || props.cell?.isSelectedEnd,
|
||||
};
|
||||
};
|
||||
|
||||
mountComponent(CollapseContainer, {
|
||||
cell: null,
|
||||
});
|
||||
);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { useEvent, useState } from 'functional-mini/component';
|
||||
import { mountComponent } from '../../../../src/_util/component';
|
||||
import { Component, getValueFromProps } from '../../../../src/_util/simply';
|
||||
|
||||
export interface Props {
|
||||
hide?: boolean;
|
||||
@ -8,22 +7,55 @@ export interface Props {
|
||||
handleClick?(id: string): void;
|
||||
}
|
||||
|
||||
const CollapseContainer = (props: Props) => {
|
||||
const [collapse, setCollapse] = useState(props.defaultCollapse ?? true);
|
||||
Component(
|
||||
{
|
||||
hide: false,
|
||||
defaultCollapse: null,
|
||||
title: '',
|
||||
} as Props,
|
||||
{
|
||||
handleToggle() {
|
||||
const { collapse } = this.data;
|
||||
this.setData({
|
||||
collapse: !collapse,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
collapse: true,
|
||||
internalHide: false,
|
||||
containerTitle: '',
|
||||
},
|
||||
null,
|
||||
{
|
||||
/// #if ALIPAY
|
||||
onInit() {
|
||||
const [defaultCollapse, hide, title] = getValueFromProps(this, [
|
||||
'defaultCollapse',
|
||||
'hide',
|
||||
'title',
|
||||
]);
|
||||
this.setData({
|
||||
collapse: defaultCollapse ?? true,
|
||||
internalHide: hide,
|
||||
containerTitle: title,
|
||||
});
|
||||
},
|
||||
/// #endif
|
||||
/// #if WECHAT
|
||||
attached() {
|
||||
const [defaultCollapse, hide, title] = getValueFromProps(this, [
|
||||
'defaultCollapse',
|
||||
'hide',
|
||||
'title',
|
||||
]);
|
||||
this.setData({
|
||||
collapse: defaultCollapse ?? true,
|
||||
internalHide: hide,
|
||||
containerTitle: title,
|
||||
});
|
||||
},
|
||||
|
||||
useEvent('handleToggle', () => {
|
||||
setCollapse((v) => !v);
|
||||
});
|
||||
|
||||
return {
|
||||
collapse,
|
||||
internalHide: props.hide,
|
||||
containerTitle: props.title,
|
||||
};
|
||||
};
|
||||
|
||||
mountComponent<Props>(CollapseContainer, {
|
||||
hide: false,
|
||||
defaultCollapse: null,
|
||||
title: '',
|
||||
});
|
||||
/// #endif
|
||||
}
|
||||
);
|
||||
|
@ -64,14 +64,6 @@ $ npm run dev:doc
|
||||
|
||||
## Ant Design Mini 的工程方案
|
||||
|
||||
### 函数式组件
|
||||
|
||||
从 v2 版本开始,我们逐步采用“React 函数式组件”开发模式来开发小程序自定义组件,背后依托 [functional-mini](https://github.com/ant-design/functional-mini) 这个 SDK。如日历组件(参见 [Calendar/index.ts](https://github.com/ant-design/ant-design-mini/blob/master/src/Calendar/index.ts))。
|
||||
|
||||
[functional-mini](https://github.com/ant-design/functional-mini) 作为运行时 SDK,接管小程序的逻辑层代码,但并不影响视图层,为我们在项目架构复杂度和编码习惯上带来平衡。借此,函数式组件的基本特性得以运用,提升代码可维护性,如数据加工逻辑组装、hooks 逻辑复用等。
|
||||
|
||||
欢迎你一同参与 Ant Design Mini 函数式组件开发,探索更佳的小程序工程形态。
|
||||
|
||||
### 使用 tsx 语法编写视图层
|
||||
|
||||
我们使用 tsx 语法编写视图层。编译器解析 tsx 语法后,生成小程序视图层代码。这意味着:
|
||||
|
@ -35,7 +35,6 @@
|
||||
"async-validator": "^4.0.7",
|
||||
"dayjs": "^1.11.3",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"functional-mini": "^0.17.0",
|
||||
"tslib": "2.5.0"
|
||||
},
|
||||
"overrides": {
|
||||
|
@ -1,44 +0,0 @@
|
||||
import { alipayComponent, wechatComponent } from 'functional-mini/component';
|
||||
|
||||
function removeNullProps(props) {
|
||||
const newProps = {};
|
||||
for (const key in props) {
|
||||
if (props[key] !== null) {
|
||||
newProps[key] = props[key];
|
||||
}
|
||||
}
|
||||
return newProps;
|
||||
}
|
||||
|
||||
export function mountComponent<T>(
|
||||
Hooks: (props: T) => unknown,
|
||||
defaultProps: T
|
||||
) {
|
||||
/// #if WECHAT
|
||||
Component(
|
||||
wechatComponent(Hooks, mergeDefaultProps(defaultProps) as unknown as T, {
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
multipleSlots: true,
|
||||
virtualHost: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
/// #endif
|
||||
|
||||
/// #if ALIPAY
|
||||
Component(
|
||||
alipayComponent(Hooks, removeNullProps(mergeDefaultProps(defaultProps)))
|
||||
);
|
||||
/// #endif
|
||||
}
|
||||
|
||||
function mergeDefaultProps(defaultProps: Record<string, any> = {}) {
|
||||
return {
|
||||
/// #if WECHAT
|
||||
className: '',
|
||||
style: '',
|
||||
/// #endif
|
||||
...defaultProps,
|
||||
};
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
import { useComponent } from 'functional-mini/component';
|
||||
import fmtEvent from '../fmtEvent';
|
||||
import { useEvent } from './useEvent';
|
||||
|
||||
export function useComponentEvent<T>(props: T) {
|
||||
const component = useComponent();
|
||||
const triggerEvent = useEvent(
|
||||
(eventName: string, value: unknown, e?: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
/// #if ALIPAY
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](value, fmtEvent(props, e));
|
||||
}
|
||||
/// #endif
|
||||
|
||||
/// #if WECHAT
|
||||
component.triggerEvent(eventName.toLocaleLowerCase(), value);
|
||||
/// #endif
|
||||
}
|
||||
);
|
||||
|
||||
const triggerEventValues = useEvent(
|
||||
(eventName: string, values: any[], e?: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
/// #if ALIPAY
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](...values, fmtEvent(props, e));
|
||||
}
|
||||
/// #endif
|
||||
|
||||
/// #if WECHAT
|
||||
component.triggerEvent(eventName.toLocaleLowerCase(), values);
|
||||
/// #endif
|
||||
}
|
||||
);
|
||||
const triggerEventOnly = useEvent((eventName: string, e?: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
/// #if ALIPAY
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](fmtEvent(props, e));
|
||||
}
|
||||
/// #endif
|
||||
|
||||
/// #if WECHAT
|
||||
component.triggerEvent(eventName.toLocaleLowerCase());
|
||||
/// #endif
|
||||
});
|
||||
|
||||
const alipayForwardCatchEvent = useEvent((eventName: string, e: any) => {
|
||||
// 首字母大写,然后加上 catch
|
||||
|
||||
/// #if ALIPAY
|
||||
const alipayCallbackName =
|
||||
'catch' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](fmtEvent(props, e));
|
||||
}
|
||||
/// #endif
|
||||
});
|
||||
|
||||
const alipayForwardEvent = useEvent((eventName: string, e: any) => {
|
||||
// 首字母大写,然后加上 on
|
||||
|
||||
/// #if ALIPAY
|
||||
const alipayCallbackName =
|
||||
'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
|
||||
|
||||
if (props[alipayCallbackName]) {
|
||||
props[alipayCallbackName](fmtEvent(props, e));
|
||||
}
|
||||
/// #endif
|
||||
});
|
||||
|
||||
return {
|
||||
triggerEvent,
|
||||
triggerEventValues,
|
||||
triggerEventOnly,
|
||||
// 转发 catch 事件
|
||||
alipayForwardCatchEvent,
|
||||
// 转发事件
|
||||
alipayForwardEvent,
|
||||
};
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useEvent.ts
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import * as React from 'functional-mini/compat';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function useEvent<T extends Function>(callback: T): T {
|
||||
const fnRef = React.useRef<any>();
|
||||
fnRef.current = callback;
|
||||
|
||||
const memoFn = React.useCallback<T>(
|
||||
((...args: any) => fnRef.current?.(...args)) as any,
|
||||
[]
|
||||
);
|
||||
|
||||
return memoFn;
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
import { useEvent } from 'functional-mini/component';
|
||||
import { platform } from '../platform';
|
||||
|
||||
export type EventHandler<T> = (value: T, e: any) => void;
|
||||
|
||||
export const useHandleCustomEvent = <T>(
|
||||
eventName: string,
|
||||
handler: EventHandler<T>
|
||||
) => {
|
||||
useEvent(
|
||||
eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(eventOrValue: any, alipayEvent?: any) => {
|
||||
/// #if ALIPAY
|
||||
if (platform() === 'alipay') {
|
||||
return handler(eventOrValue, alipayEvent);
|
||||
}
|
||||
/// #endif
|
||||
|
||||
/// #if WECHAT
|
||||
return handler(eventOrValue.detail, eventOrValue);
|
||||
/// #endif
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export type MultipleValueEventHandler<T> = (...args: any[]) => void;
|
||||
|
||||
export const useMultipleValueHandleCustomEvent = <T extends any[]>(
|
||||
eventName: string,
|
||||
handler: MultipleValueEventHandler<T>
|
||||
) => {
|
||||
useEvent(
|
||||
eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(...args: any[]) => {
|
||||
/// #if ALIPAY
|
||||
if (platform() === 'alipay') {
|
||||
return handler(...args);
|
||||
}
|
||||
/// #endif
|
||||
|
||||
/// #if WECHAT
|
||||
const firstArgs = args[0];
|
||||
if (Array.isArray(firstArgs.detail)) {
|
||||
const wechatArgs = firstArgs.detail.concat(firstArgs);
|
||||
return handler(...wechatArgs);
|
||||
} else {
|
||||
return handler([firstArgs.detail, firstArgs]);
|
||||
}
|
||||
/// #endif
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export type EventOnlyHandler = (e: any) => void;
|
||||
|
||||
export const useHandleCustomEventOnly = (
|
||||
eventName: string,
|
||||
handler: EventOnlyHandler
|
||||
) => {
|
||||
useEvent(
|
||||
eventName,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(event) => {
|
||||
/// #if ALIPAY
|
||||
if (platform() === 'alipay') {
|
||||
return handler(event);
|
||||
}
|
||||
/// #endif
|
||||
|
||||
/// #if WECHAT
|
||||
return handler(event);
|
||||
/// #endif
|
||||
}
|
||||
);
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
import { useComponent } from 'functional-mini/component';
|
||||
import { getInstanceBoundingClientRect } from '../jsapi/get-instance-bounding-client-rect';
|
||||
|
||||
export const useInstanceBoundingClientRect = () => {
|
||||
const instance = useComponent();
|
||||
function getInstance() {
|
||||
if (instance.$id) {
|
||||
return my;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
async function getBoundingClientRectWithId(prefix: string) {
|
||||
return await getInstanceBoundingClientRect(
|
||||
getInstance(),
|
||||
`${prefix}${instance.$id ? `-${instance.$id}` : ''}`
|
||||
);
|
||||
}
|
||||
async function getBoundingClientRect(query: string) {
|
||||
return await getInstanceBoundingClientRect(getInstance(), query);
|
||||
}
|
||||
|
||||
async function getBoundingClientRectWithBuilder(
|
||||
builder: (id: string) => string
|
||||
) {
|
||||
return await getInstanceBoundingClientRect(
|
||||
getInstance(),
|
||||
builder(instance.$id ? `-${instance.$id}` : '')
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
getBoundingClientRect,
|
||||
getBoundingClientRectWithId,
|
||||
getBoundingClientRectWithBuilder,
|
||||
};
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useLayoutEffect.ts
|
||||
*/
|
||||
|
||||
import * as React from 'functional-mini/compat';
|
||||
|
||||
/**
|
||||
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
||||
*/
|
||||
const useInternalLayoutEffect = React.useEffect;
|
||||
|
||||
const useLayoutEffect = (callback: (mount: boolean) => void, deps?: any) => {
|
||||
const firstMountRef = React.useRef(true);
|
||||
|
||||
useInternalLayoutEffect(() => {
|
||||
return callback(firstMountRef.current);
|
||||
}, deps);
|
||||
|
||||
// We tell react that first mount has passed
|
||||
useInternalLayoutEffect(() => {
|
||||
firstMountRef.current = false;
|
||||
return () => {
|
||||
firstMountRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
|
||||
export const useComponentUpdateEffect: typeof React.useEffect = (
|
||||
callback,
|
||||
deps
|
||||
) => {
|
||||
useLayoutEffect((firstMount) => {
|
||||
if (!firstMount) {
|
||||
return callback();
|
||||
}
|
||||
}, deps);
|
||||
};
|
||||
|
||||
export default useLayoutEffect;
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useMergedState.ts
|
||||
*/
|
||||
import { useEvent } from './useEvent';
|
||||
import { useComponentUpdateEffect } from './useLayoutEffect';
|
||||
import { useSafeState as useState } from './useState';
|
||||
import { supportUndefinedProperty } from '../platform';
|
||||
|
||||
type Updater<T> = (
|
||||
updater: T | ((origin: T) => T),
|
||||
ignoreDestroy?: boolean
|
||||
) => void;
|
||||
|
||||
/** We only think `undefined` is empty */
|
||||
export function hasValue(value: any) {
|
||||
if (supportUndefinedProperty()) {
|
||||
return value !== undefined;
|
||||
}
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `useState` but will use props value if provided.
|
||||
* Note that internal use rc-util `useState` hook.
|
||||
*/
|
||||
export function useMergedState<T, R = T>(
|
||||
defaultStateValue: T | (() => T),
|
||||
option?: {
|
||||
defaultValue?: T | (() => T);
|
||||
value?: T;
|
||||
onChange?: (value: T, prevValue: T) => void;
|
||||
postState?: (value: T) => T;
|
||||
}
|
||||
): [R, Updater<T>] {
|
||||
const { defaultValue, value, onChange, postState } = option || {};
|
||||
|
||||
// ======================= Init =======================
|
||||
const [innerValue, setInnerValue] = useState<T>(() => {
|
||||
if (hasValue(value)) {
|
||||
return value;
|
||||
} else if (hasValue(defaultValue)) {
|
||||
return typeof defaultValue === 'function'
|
||||
? (defaultValue as any)()
|
||||
: defaultValue;
|
||||
} else {
|
||||
return typeof defaultStateValue === 'function'
|
||||
? (defaultStateValue as any)()
|
||||
: defaultStateValue;
|
||||
}
|
||||
});
|
||||
|
||||
const mergedValue = hasValue(value) ? value : innerValue;
|
||||
const postMergedValue = postState ? postState(mergedValue) : mergedValue;
|
||||
|
||||
// ====================== Change ======================
|
||||
const onChangeFn = useEvent(onChange);
|
||||
|
||||
const [prevValue, setPrevValue] = useState<[T]>([mergedValue]);
|
||||
|
||||
useComponentUpdateEffect(() => {
|
||||
const prev = prevValue[0];
|
||||
if (innerValue !== prev) {
|
||||
onChangeFn(innerValue, prev);
|
||||
}
|
||||
}, [prevValue]);
|
||||
|
||||
// Sync value back to `undefined` when it from control to un-control
|
||||
useComponentUpdateEffect(() => {
|
||||
if (!hasValue(value)) {
|
||||
setInnerValue(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
// ====================== Update ======================
|
||||
const triggerChange: Updater<T> = useEvent((updater, ignoreDestroy) => {
|
||||
setInnerValue(updater, ignoreDestroy);
|
||||
setPrevValue([mergedValue], ignoreDestroy);
|
||||
});
|
||||
|
||||
return [postMergedValue as unknown as R, triggerChange];
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
import { useEvent } from './useEvent';
|
||||
import { useComponentUpdateEffect } from './useLayoutEffect';
|
||||
import { hasValue } from './useMergedState';
|
||||
import { useSafeState as useState } from './useState';
|
||||
|
||||
type Updater<T> = (
|
||||
updater: T | ((old: T) => T),
|
||||
ignoreDestroy?: boolean
|
||||
) => void;
|
||||
|
||||
export function useMixState<T, R = T, O = undefined>(
|
||||
defaultStateValue: T | (() => T),
|
||||
option?: {
|
||||
defaultValue?: T | (() => T);
|
||||
value?: T;
|
||||
postState?: (
|
||||
value: T,
|
||||
option?: O
|
||||
) => { valid: true; value: T } | { valid: false };
|
||||
}
|
||||
): [
|
||||
R,
|
||||
{
|
||||
isControlled: boolean;
|
||||
triggerUpdater: (value: (old: T) => T, option?: O) => void;
|
||||
update(
|
||||
value: T,
|
||||
option?: O
|
||||
): { changed: true; newValue: T } | { changed: false };
|
||||
}
|
||||
] {
|
||||
const {
|
||||
defaultValue,
|
||||
value,
|
||||
postState = (v) => ({ valid: true, value: v }),
|
||||
} = option || {};
|
||||
|
||||
// ======================= Init =======================
|
||||
const [innerValue, setInnerValue] = useState<T>(() => {
|
||||
let v;
|
||||
if (hasValue(value)) {
|
||||
v = value;
|
||||
} else if (hasValue(defaultValue)) {
|
||||
v =
|
||||
typeof defaultValue === 'function'
|
||||
? (defaultValue as any)()
|
||||
: defaultValue;
|
||||
} else {
|
||||
v =
|
||||
typeof defaultStateValue === 'function'
|
||||
? (defaultStateValue as any)()
|
||||
: defaultStateValue;
|
||||
}
|
||||
const state = postState(v);
|
||||
if (state.valid) {
|
||||
return state.value;
|
||||
}
|
||||
});
|
||||
|
||||
const state = postState(value);
|
||||
const merge = hasValue(value) && state.valid ? state.value : innerValue;
|
||||
|
||||
useComponentUpdateEffect(() => {
|
||||
const state = postState(value);
|
||||
if (state.valid) {
|
||||
setInnerValue(state.value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const isControlled = hasValue(value);
|
||||
const triggerChange: Updater<T> = useEvent((newState, ignoreDestroy) => {
|
||||
setInnerValue(newState, ignoreDestroy);
|
||||
});
|
||||
|
||||
const triggerUpdate = useEvent((value, option) => {
|
||||
const state = postState(value, option);
|
||||
if (state.valid && state.value !== innerValue) {
|
||||
triggerChange(state.value);
|
||||
return { changed: true, newValue: state.value };
|
||||
}
|
||||
return { changed: false };
|
||||
});
|
||||
|
||||
const triggerUpdater: (value: (old: T) => T, option?: O) => void = useEvent(
|
||||
(getValue, option) => {
|
||||
if (isControlled) {
|
||||
getValue(merge);
|
||||
} else {
|
||||
triggerChange((old: T): T => {
|
||||
const newValue = getValue(old);
|
||||
const state = postState(newValue, option);
|
||||
if (state.valid && state.value !== innerValue) {
|
||||
return state.value;
|
||||
}
|
||||
return old;
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return [
|
||||
merge as unknown as R,
|
||||
{
|
||||
isControlled,
|
||||
update: triggerUpdate as any,
|
||||
triggerUpdater,
|
||||
},
|
||||
];
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { useComponent, useEffect } from 'functional-mini/component';
|
||||
|
||||
export const triggerRefEvent = () => {
|
||||
/// #if WECHAT
|
||||
const component = useComponent();
|
||||
useEffect(() => {
|
||||
component.triggerEvent('ref', component);
|
||||
}, []);
|
||||
/// #endif
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
/**
|
||||
* copy from https://github.com/react-component/util/blob/9d5cb8946da29e690bead78b2c251da6f7cbd0eb/src/hooks/useState.ts
|
||||
*/
|
||||
|
||||
import * as React from 'functional-mini/compat';
|
||||
|
||||
type Updater<T> = T | ((prevValue: T) => T);
|
||||
|
||||
export type SetState<T> = (
|
||||
nextValue: Updater<T>,
|
||||
/**
|
||||
* Will not update state when destroyed.
|
||||
* Developer should make sure this is safe to ignore.
|
||||
*/
|
||||
ignoreDestroy?: boolean
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Same as React.useState but `setState` accept `ignoreDestroy` param to not to setState after destroyed.
|
||||
* We do not make this auto is to avoid real memory leak.
|
||||
* Developer should confirm it's safe to ignore themselves.
|
||||
*/
|
||||
export function useSafeState<T>(
|
||||
defaultValue?: T | (() => T)
|
||||
): [T, SetState<T>] {
|
||||
const destroyRef = React.useRef(false);
|
||||
const [value, setValue] = React.useState(defaultValue);
|
||||
|
||||
React.useEffect(() => {
|
||||
destroyRef.current = false;
|
||||
|
||||
return () => {
|
||||
destroyRef.current = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
function safeSetState(updater: Updater<T>, ignoreDestroy?: boolean) {
|
||||
if (ignoreDestroy && destroyRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setValue(updater);
|
||||
}
|
||||
|
||||
return [value, safeSetState];
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
export function triggerComponentEvent(instance, propsName, event) {
|
||||
/// #if WECHAT
|
||||
instance.triggerEvent(propsName, event.detail);
|
||||
/// #endif
|
||||
|
||||
/// #if ALIPAY
|
||||
if (instance.props[propsName]) {
|
||||
instance.props[propsName](event);
|
||||
}
|
||||
/// #endif
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
import { useEvent, useState, alipayComponent } from 'functional-mini/component';
|
||||
import { sleep, createInstance } from '../../../utils';
|
||||
import { expect, it } from 'vitest';
|
||||
import {
|
||||
useHandleCustomEvent,
|
||||
useMultipleValueHandleCustomEvent,
|
||||
useHandleCustomEventOnly,
|
||||
} from 'compiled-alipay/_util/hooks/useHandleCustomEvent';
|
||||
import fmtEvent from 'compiled-alipay/_util/fmtEvent';
|
||||
|
||||
const testMy = {
|
||||
canIUse() {
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
it('test useHandleCustomEvent', async () => {
|
||||
const Test = () => {
|
||||
const [count, setCount] = useState(1);
|
||||
useHandleCustomEvent('handleEvent', (value, event) => {
|
||||
return {
|
||||
value,
|
||||
event,
|
||||
count,
|
||||
};
|
||||
});
|
||||
useEvent('updateCount', function (v) {
|
||||
setCount(v);
|
||||
return 'ok';
|
||||
});
|
||||
return {
|
||||
count,
|
||||
};
|
||||
};
|
||||
|
||||
const componentOptions = alipayComponent(Test, {});
|
||||
const instance = createInstance(componentOptions as any, {}, testMy);
|
||||
expect(
|
||||
instance.callMethod('handleEvent', 2, fmtEvent({ 'data-a': 1 })).count
|
||||
).toBe(1);
|
||||
expect(instance.callMethod('updateCount', 10)).toEqual('ok');
|
||||
await sleep(20);
|
||||
expect(instance.getData().count).toEqual(10);
|
||||
expect(
|
||||
instance.callMethod('handleEvent', 2, fmtEvent({ 'data-a': 1 }))
|
||||
).toEqual({
|
||||
value: 2,
|
||||
event: {
|
||||
currentTarget: { dataset: { 'a': 1 } },
|
||||
target: { dataset: { 'a': 1 }, targetDataset: { 'a': 1 } },
|
||||
},
|
||||
count: 10,
|
||||
});
|
||||
expect(instance.callMethod('updateCount', 30)).toEqual('ok');
|
||||
await sleep(20);
|
||||
expect(instance.getData().count).toEqual(30);
|
||||
});
|
||||
|
||||
it('test useMultipleValueHandleCustomEvent', async () => {
|
||||
const Test = () => {
|
||||
useMultipleValueHandleCustomEvent('handleEvent', (...args) => {
|
||||
return {
|
||||
args,
|
||||
};
|
||||
});
|
||||
return {};
|
||||
};
|
||||
|
||||
const componentOptions = alipayComponent(Test, {});
|
||||
const instance = createInstance(componentOptions as any, {}, testMy);
|
||||
expect(
|
||||
instance.callMethod('handleEvent', 1, 2, fmtEvent({ 'data-a': 1 }))
|
||||
).toEqual({
|
||||
args: [
|
||||
1,
|
||||
2,
|
||||
{
|
||||
currentTarget: { dataset: { 'a': 1 } },
|
||||
target: { dataset: { 'a': 1 }, targetDataset: { 'a': 1 } },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(instance.callMethod('handleEvent')).toEqual({
|
||||
args: [],
|
||||
});
|
||||
|
||||
expect(instance.callMethod('handleEvent', fmtEvent({ 'data-a': 1 }))).toEqual(
|
||||
{
|
||||
args: [
|
||||
{
|
||||
currentTarget: { dataset: { 'a': 1 } },
|
||||
target: { dataset: { 'a': 1 }, targetDataset: { 'a': 1 } },
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('test useHandleCustomEventOnly', async () => {
|
||||
const Test = () => {
|
||||
useHandleCustomEventOnly('handleEvent', (...args) => {
|
||||
return {
|
||||
args,
|
||||
};
|
||||
});
|
||||
return {};
|
||||
};
|
||||
|
||||
const componentOptions = alipayComponent(Test, {}) as any;
|
||||
const instance = createInstance(componentOptions, {}, testMy);
|
||||
expect(instance.callMethod('handleEvent', fmtEvent({ 'data-a': 1 }))).toEqual(
|
||||
{
|
||||
args: [
|
||||
{
|
||||
currentTarget: { dataset: { 'a': 1 } },
|
||||
target: { dataset: { 'a': 1 }, targetDataset: { 'a': 1 } },
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
});
|
@ -10,11 +10,6 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
test: {
|
||||
server: {
|
||||
deps: {
|
||||
inline: [/functional-mini/],
|
||||
},
|
||||
},
|
||||
watch: true,
|
||||
globals: true,
|
||||
setupFiles: ['./tests/setup.ts'],
|
||||
|
Loading…
Reference in New Issue
Block a user