Skip to content

Commit 133569d

Browse files
committed
chore: modify export type
1 parent f792a3c commit 133569d

8 files changed

Lines changed: 381 additions & 77 deletions

File tree

src/__tests__/react-form-simple.test.tsx

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,3 +1441,330 @@ describe('React Form Simple - 完整测试套件', () => {
14411441
});
14421442
});
14431443
});
1444+
1445+
describe.concurrent('dymic form', () => {
1446+
test('add', async ({ expect }) => {
1447+
const TestDemo = React.forwardRef((props, ref) => {
1448+
const { render, model, forceUpdate } = useForm<{
1449+
list: Array<{ uid: string; value: string }>;
1450+
}>({ list: [] });
1451+
const renderMapList = model.list.map((v, index) => {
1452+
return (
1453+
<div key={v.uid} id={v.uid}>
1454+
{render(`list.${index}.value`)(
1455+
<input id={`dymic-${index}-input`} />,
1456+
)}
1457+
</div>
1458+
);
1459+
});
1460+
const renderButton = (
1461+
<button
1462+
id="dymic-add-button"
1463+
onClick={() => {
1464+
model.list.push({
1465+
uid: getUuid(),
1466+
value: `${model.list.length}`,
1467+
});
1468+
forceUpdate();
1469+
}}
1470+
>
1471+
add
1472+
</button>
1473+
);
1474+
useImperativeHandle(ref, () => ({}));
1475+
return (
1476+
<>
1477+
<div id="add-dymic-wrap">{renderMapList}</div>
1478+
{renderButton}
1479+
</>
1480+
);
1481+
});
1482+
const { container } = testRender(<TestDemo />);
1483+
const button = container.querySelector(
1484+
'#dymic-add-button',
1485+
) as HTMLButtonElement;
1486+
button.click();
1487+
await vi.waitFor(
1488+
() => {
1489+
const wrap = container.querySelector(
1490+
'#add-dymic-wrap',
1491+
) as HTMLDivElement;
1492+
if (wrap.children.length > 0) {
1493+
return true;
1494+
}
1495+
return Promise.reject();
1496+
},
1497+
{ timeout: 100, interval: 10 },
1498+
);
1499+
const wrap = container.querySelector('#add-dymic-wrap') as HTMLDivElement;
1500+
expect(wrap.children.length).toBeGreaterThan(0);
1501+
const children = wrap.children;
1502+
Array.from(children).forEach((v, index) => {
1503+
const input = container.querySelector(
1504+
`#dymic-${index}-input`,
1505+
) as HTMLInputElement;
1506+
expect(Number(input.value)).toBe(index);
1507+
});
1508+
});
1509+
1510+
test('remove', async ({ expect }) => {
1511+
const TestDemo = React.forwardRef((props, ref) => {
1512+
const { render, model, forceUpdate } = useForm<{
1513+
list: Array<{ uid: string; value: string }>;
1514+
}>({ list: [] });
1515+
const renderMapList = model.list.map((v, index) => {
1516+
const renderRemoveButton = (
1517+
<button
1518+
id={`remove-item-${index}-button`}
1519+
onClick={() => {
1520+
model.list.splice(index, 1);
1521+
forceUpdate();
1522+
}}
1523+
>
1524+
remove!
1525+
</button>
1526+
);
1527+
return (
1528+
<div id={v.uid} key={v.uid}>
1529+
{render(`list.${index}.value`)(
1530+
<input id={`dymic-remove-${index}-input`} />,
1531+
)}
1532+
{renderRemoveButton}
1533+
</div>
1534+
);
1535+
});
1536+
const renderButton = (
1537+
<button
1538+
id="dymic-remove-add-button"
1539+
onClick={() => {
1540+
model.list.push({
1541+
uid: getUuid(),
1542+
value: `${model.list.length}`,
1543+
});
1544+
forceUpdate();
1545+
}}
1546+
>
1547+
add
1548+
</button>
1549+
);
1550+
useImperativeHandle(ref, () => ({
1551+
getModalData() {
1552+
return model;
1553+
},
1554+
set(arr: any[]) {
1555+
model.list = arr;
1556+
forceUpdate();
1557+
},
1558+
}));
1559+
return (
1560+
<>
1561+
<div id="remove-dymic-wrap">{renderMapList}</div>
1562+
{renderButton}
1563+
</>
1564+
);
1565+
});
1566+
1567+
const demoRef = React.createRef() as any;
1568+
1569+
const { container } = testRender(<TestDemo ref={demoRef} />);
1570+
const addItem = (count: number = 1) => {
1571+
const button = container.querySelector(
1572+
'#dymic-remove-add-button',
1573+
) as HTMLButtonElement;
1574+
Array.from({ length: count }, (x, y) => y).forEach(() => {
1575+
button.click();
1576+
});
1577+
};
1578+
1579+
addItem(2);
1580+
1581+
const getWrap = () =>
1582+
container.querySelector('#remove-dymic-wrap') as HTMLDivElement;
1583+
1584+
const getLen = () => {
1585+
const wrap = getWrap();
1586+
return wrap?.children?.length;
1587+
};
1588+
1589+
const checkWrapChildrenLen = () => {
1590+
const len = getLen();
1591+
if (len === 2) {
1592+
return true;
1593+
}
1594+
return Promise.reject();
1595+
};
1596+
await vi.waitFor(() => checkWrapChildrenLen(), {
1597+
timeout: 100,
1598+
interval: 10,
1599+
});
1600+
1601+
const len = getLen();
1602+
expect(len).toBeGreaterThan(0);
1603+
const getInput = (index: number) => {
1604+
const input = container.querySelector(
1605+
`#dymic-remove-${index}-input`,
1606+
) as HTMLInputElement;
1607+
return input;
1608+
};
1609+
const getInputValue = (index: number) => {
1610+
const input = getInput(index);
1611+
return input.value;
1612+
};
1613+
const checkInputValue = () => {
1614+
const wrap = getWrap();
1615+
const children = wrap.children;
1616+
Array.from(children).forEach((v, index) => {
1617+
const value = getInputValue(index);
1618+
expect(Number(value)).toBe(index);
1619+
});
1620+
};
1621+
checkInputValue();
1622+
const removeAction = async () => {
1623+
const removeButton = container.querySelector(
1624+
'#remove-item-0-button',
1625+
) as HTMLButtonElement;
1626+
1627+
removeButton.click();
1628+
await vi.waitFor(() => {
1629+
const len = getLen();
1630+
if (len === 1) {
1631+
return true;
1632+
}
1633+
return Promise.reject();
1634+
});
1635+
// checkInputValue();
1636+
1637+
addItem();
1638+
1639+
const changeInputValue = (index: number) => {
1640+
const input = getInput(index);
1641+
fireEvent.change(input, { target: { value: 'testtest' } });
1642+
};
1643+
1644+
await vi.waitFor(() => {
1645+
const len = getLen();
1646+
if (len === 2) return true;
1647+
return Promise.reject();
1648+
});
1649+
1650+
changeInputValue(0);
1651+
1652+
expect(getInputValue(0)).toBe('testtest');
1653+
1654+
expect(getInputValue(0)).not.toBe(getInputValue(1));
1655+
const getModal = () => {
1656+
const model = demoRef.current?.getModalData?.();
1657+
return model;
1658+
};
1659+
const getModelListValue = (index: number) => {
1660+
const model = getModal();
1661+
const list = model.list || [];
1662+
return list[index].value;
1663+
};
1664+
1665+
expect(getModelListValue(0)).toBe(getInputValue(0));
1666+
expect(getModelListValue(0)).not.toBe(getModelListValue(1));
1667+
1668+
return Promise.resolve();
1669+
};
1670+
1671+
await removeAction();
1672+
});
1673+
1674+
test('assignment', async () => {
1675+
const TestDemo = React.forwardRef(({}, ref) => {
1676+
const { render, model, forceUpdate } = useForm<{
1677+
list: Array<{ uid: string; value: string }>;
1678+
}>({ list: [] });
1679+
const renderMapList = model.list.map((v, index) => {
1680+
return (
1681+
<div id={v.uid} key={v.uid}>
1682+
{render(`list.${index}.value`)(
1683+
<input id={`dymic-assignment-${index}-input`} />,
1684+
)}
1685+
</div>
1686+
);
1687+
});
1688+
1689+
useImperativeHandle(ref, () => ({
1690+
getModalData() {
1691+
return model;
1692+
},
1693+
set(arr: any[]) {
1694+
model.list = arr;
1695+
forceUpdate();
1696+
},
1697+
}));
1698+
return (
1699+
<>
1700+
<div id="assign-dymic-wrap">{renderMapList}</div>
1701+
</>
1702+
);
1703+
});
1704+
1705+
const ref = React.createRef() as any;
1706+
const { container } = testRender(<TestDemo ref={ref} />);
1707+
1708+
const arr = [
1709+
{ uid: getUuid(), value: 'name' },
1710+
{ uid: getUuid(), value: 'age' },
1711+
];
1712+
ref.current.set(arr);
1713+
1714+
const getWrap = () =>
1715+
container.querySelector('#assign-dymic-wrap') as HTMLDivElement;
1716+
1717+
const getLen = () => {
1718+
const wrap = getWrap();
1719+
return wrap?.children?.length;
1720+
};
1721+
1722+
const checkWrapChildrenLen = () => {
1723+
const len = getLen();
1724+
if (len === 2) {
1725+
return true;
1726+
}
1727+
return Promise.reject();
1728+
};
1729+
1730+
const getInput = (index: number) => {
1731+
const input = container.querySelector(
1732+
`#dymic-assignment-${index}-input`,
1733+
) as HTMLInputElement;
1734+
return input;
1735+
};
1736+
const getInputValue = (index: number) => {
1737+
const input = getInput(index);
1738+
return input.value;
1739+
};
1740+
1741+
const getModal = () => {
1742+
const model = ref.current?.getModalData?.();
1743+
return model;
1744+
};
1745+
1746+
const getModelListValue = (index: number) => {
1747+
const model = getModal();
1748+
const list = model.list || [];
1749+
return list[index].value;
1750+
};
1751+
1752+
await vi.waitFor(() => checkWrapChildrenLen());
1753+
1754+
Array.from(getWrap().children).forEach((v, index) => {
1755+
const inputValue = getInputValue(index);
1756+
expect(inputValue).toBe(arr[index].value);
1757+
expect(inputValue).toBe(getModelListValue(index));
1758+
});
1759+
1760+
fireEvent.change(getInput(0), { target: { value: 'testtest' } });
1761+
1762+
fireEvent.change(getInput(1), { target: { value: 'testtesttwo' } });
1763+
1764+
expect(getModelListValue(0)).toBe(getInputValue(0));
1765+
1766+
expect(getModelListValue(1)).toBe(getInputValue(1));
1767+
1768+
expect(getModelListValue(0)).not.toBe(getInputValue(1));
1769+
});
1770+
});

src/driver/ControllerDriver/controller.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ export type ObserverOptions = {
1010
onArrayChange?: () => void;
1111
};
1212

13-
// 简化的目标对象克隆
1413
export const cloneTarget = (proxy: any) => cloneDeep(proxy);
1514

16-
// 优化的值获取函数
1715
export const getProxyValue = (obj: any, path: string): any => {
1816
if (!path || typeof path !== 'string') return undefined;
1917

@@ -34,7 +32,6 @@ export const getProxyValue = (obj: any, path: string): any => {
3432
return current;
3533
};
3634

37-
// 优化的值设置函数 - 修复响应式丢失问题
3835
export const updateProxyValue = (obj: any, path: string, value: any): void => {
3936
if (!path || typeof path !== 'string') return;
4037

@@ -80,7 +77,6 @@ export const updateProxyValue = (obj: any, path: string, value: any): void => {
8077
}
8178
};
8279

83-
// 简化的特殊对象检测
8480
const isSpecialObject = (obj: any): boolean => {
8581
if (!obj || typeof obj !== 'object') return false;
8682

@@ -96,7 +92,6 @@ const isSpecialObject = (obj: any): boolean => {
9692
);
9793
};
9894

99-
// 大幅简化的replaceTarget函数
10095
export const replaceTarget = (target: any, source: any): any => {
10196
if (!isObject(target) || !isObject(source)) {
10297
return source;
@@ -144,8 +139,7 @@ export const replaceTarget = (target: any, source: any): any => {
144139
return target;
145140
};
146141

147-
// 优化的观察者创建函数
148-
export const observer = <T extends DefaultRecord>(
142+
const observer = <T extends DefaultRecord>(
149143
target: T,
150144
callback: ObserverCallback,
151145
options: ObserverOptions = {},
@@ -202,5 +196,4 @@ export const observer = <T extends DefaultRecord>(
202196
});
203197
};
204198

205-
// 向后兼容的导出
206199
export const createObserverForm = observer;
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
1-
export * from './controller';
1+
export {
2+
cloneTarget,
3+
createObserverForm,
4+
getProxyValue,
5+
replaceTarget,
6+
updateProxyValue,
7+
} from './controller';

0 commit comments

Comments
 (0)