Skip to content

Commit

Permalink
feat: autoAlign pos (#405)
Browse files Browse the repository at this point in the history
* feat: autoAlign pos

* chore: fix lint

* test: add test case
  • Loading branch information
zombieJ committed Jun 29, 2023
1 parent cf29179 commit 2af861f
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 12 deletions.
21 changes: 19 additions & 2 deletions docs/examples/inside.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
/* eslint no-console:0 */
import React from 'react';
import '../../assets/index.less';
import Trigger from '../../src';
import Trigger, { BuildInPlacements } from '../../src';

export const builtinPlacements = {
const experimentalConfig = {
_experimental: {
dynamicInset: true,
},
};

export const builtinPlacements: BuildInPlacements = {
top: {
points: ['bc', 'tc'],
overflow: {
shiftX: 0,
adjustY: true,
},
offset: [0, 0],
...experimentalConfig,
},
topLeft: {
points: ['bl', 'tl'],
Expand All @@ -19,6 +26,7 @@ export const builtinPlacements = {
adjustY: true,
},
offset: [0, 0],
...experimentalConfig,
},
topRight: {
points: ['br', 'tr'],
Expand All @@ -27,6 +35,7 @@ export const builtinPlacements = {
adjustY: true,
},
offset: [0, 0],
...experimentalConfig,
},
left: {
points: ['cr', 'cl'],
Expand All @@ -35,6 +44,7 @@ export const builtinPlacements = {
shiftY: true,
},
offset: [0, 0],
...experimentalConfig,
},
leftTop: {
points: ['tr', 'tl'],
Expand All @@ -43,6 +53,7 @@ export const builtinPlacements = {
adjustY: true,
},
offset: [0, 0],
...experimentalConfig,
},
leftBottom: {
points: ['br', 'bl'],
Expand All @@ -51,6 +62,7 @@ export const builtinPlacements = {
adjustY: true,
},
offset: [0, 0],
...experimentalConfig,
},
right: {
points: ['cl', 'cr'],
Expand All @@ -59,6 +71,7 @@ export const builtinPlacements = {
shiftY: true,
},
offset: [0, 0],
...experimentalConfig,
},
bottom: {
points: ['tc', 'bc'],
Expand All @@ -67,6 +80,7 @@ export const builtinPlacements = {
adjustY: true,
},
offset: [0, 0],
...experimentalConfig,
},
};

Expand Down Expand Up @@ -106,6 +120,9 @@ export default () => {
style={{
width: `300vw`,
height: `300vh`,
// width: 500,
// height: 500,
background: `rgba(0, 0, 255, 0.1)`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
Expand Down
46 changes: 36 additions & 10 deletions src/Popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export interface PopupProps {
ready: boolean;
offsetX: number;
offsetY: number;
offsetR: number;
offsetB: number;
onAlign: VoidFunction;
onPrepare: () => Promise<void>;

Expand Down Expand Up @@ -103,6 +105,8 @@ const Popup = React.forwardRef<HTMLDivElement, PopupProps>((props, ref) => {
ready,
offsetX,
offsetY,
offsetR,
offsetB,
onAlign,
onPrepare,

Expand Down Expand Up @@ -136,16 +140,38 @@ const Popup = React.forwardRef<HTMLDivElement, PopupProps>((props, ref) => {
}

// >>>>> Offset
const offsetStyle: React.CSSProperties =
ready || !open
? {
left: offsetX,
top: offsetY,
}
: {
left: '-1000vw',
top: '-1000vh',
};
const AUTO = 'auto' as const;

const offsetStyle: React.CSSProperties = {
left: '-1000vw',
top: '-1000vh',
right: AUTO,
bottom: AUTO,
};

// Set align style
if (ready || !open) {
const { points, _experimental } = align;
const dynamicInset = _experimental?.dynamicInset;
const alignRight = dynamicInset && points[0][1] === 'r';
const alignBottom = dynamicInset && points[0][0] === 'b';

if (alignRight) {
offsetStyle.right = offsetR;
offsetStyle.left = AUTO;
} else {
offsetStyle.left = offsetX;
offsetStyle.right = AUTO;
}

if (alignBottom) {
offsetStyle.bottom = offsetB;
offsetStyle.top = AUTO;
} else {
offsetStyle.top = offsetY;
offsetStyle.bottom = AUTO;
}
}

// >>>>> Misc
const miscStyle: React.CSSProperties = {};
Expand Down
30 changes: 30 additions & 0 deletions src/hooks/useAlign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ export default function useAlign(
ready: boolean,
offsetX: number,
offsetY: number,
offsetR: number,
offsetB: number,
arrowX: number,
arrowY: number,
scaleX: number,
Expand All @@ -110,6 +112,8 @@ export default function useAlign(
ready: boolean;
offsetX: number;
offsetY: number;
offsetR: number;
offsetB: number;
arrowX: number;
arrowY: number;
scaleX: number;
Expand All @@ -119,6 +123,8 @@ export default function useAlign(
ready: false,
offsetX: 0,
offsetY: 0,
offsetR: 0,
offsetB: 0,
arrowX: 0,
arrowY: 0,
scaleX: 1,
Expand Down Expand Up @@ -160,6 +166,8 @@ export default function useAlign(

const originLeft = popupElement.style.left;
const originTop = popupElement.style.top;
const originRight = popupElement.style.right;
const originBottom = popupElement.style.bottom;

const doc = popupElement.ownerDocument;
const win = getWin(popupElement);
Expand All @@ -173,6 +181,8 @@ export default function useAlign(
// Reset first
popupElement.style.left = '0';
popupElement.style.top = '0';
popupElement.style.right = 'auto';
popupElement.style.bottom = 'auto';

// Calculate align style, we should consider `transform` case
let targetRect: Rect;
Expand Down Expand Up @@ -244,9 +254,19 @@ export default function useAlign(
? visibleRegionArea
: visibleArea;

// Record right & bottom align data
popupElement.style.left = 'auto';
popupElement.style.top = 'auto';
popupElement.style.right = '0';
popupElement.style.bottom = '0';

const popupMirrorRect = popupElement.getBoundingClientRect();

// Reset back
popupElement.style.left = originLeft;
popupElement.style.top = originTop;
popupElement.style.right = originRight;
popupElement.style.bottom = originBottom;

// Calculate scale
const scaleX = toNum(
Expand Down Expand Up @@ -622,10 +642,18 @@ export default function useAlign(

onPopupAlign?.(popupEle, nextAlignInfo);

// Additional calculate right & bottom position
const offsetX4Right =
popupMirrorRect.right - popupRect.x - (nextOffsetX + popupRect.width);
const offsetY4Bottom =
popupMirrorRect.bottom - popupRect.y - (nextOffsetY + popupRect.height);

setOffsetInfo({
ready: true,
offsetX: nextOffsetX / scaleX,
offsetY: nextOffsetY / scaleY,
offsetR: offsetX4Right / scaleX,
offsetB: offsetY4Bottom / scaleY,
arrowX: nextArrowX / scaleX,
arrowY: nextArrowY / scaleY,
scaleX,
Expand Down Expand Up @@ -667,6 +695,8 @@ export default function useAlign(
offsetInfo.ready,
offsetInfo.offsetX,
offsetInfo.offsetY,
offsetInfo.offsetR,
offsetInfo.offsetB,
offsetInfo.arrowX,
offsetInfo.arrowY,
offsetInfo.scaleX,
Expand Down
4 changes: 4 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ export function generateTrigger(
ready,
offsetX,
offsetY,
offsetR,
offsetB,
arrowX,
arrowY,
scaleX,
Expand Down Expand Up @@ -659,6 +661,8 @@ export function generateTrigger(
ready={ready}
offsetX={offsetX}
offsetY={offsetY}
offsetR={offsetR}
offsetB={offsetB}
onAlign={triggerAlign}
// Stretch
stretch={stretch}
Expand Down
11 changes: 11 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ export interface AlignType {
* Such as ['tr','cc'], align top right point of source node with center point of target node.
* Point can be 't'(top), 'b'(bottom), 'c'(center), 'l'(left), 'r'(right) */
points?: (string | AlignPoint)[];

/**
* @private Do not use in your production code
*/
_experimental?: {
/**
* @private Do not use in your production code. Auto adjust align logic
*/
dynamicInset?: boolean;
};

/**
* offset source node by offset[0] in x and offset[1] in y.
* If offset contains percentage string value, it is relative to sourceNode region.
Expand Down
25 changes: 25 additions & 0 deletions tests/align.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ describe('Trigger.Align', () => {
y: 100,
width: 100,
height: 100,
right: 200,
bottom: 200,
}),
});

Expand Down Expand Up @@ -233,4 +235,27 @@ describe('Trigger.Align', () => {
top: `50px`,
});
});

it('support dynamicInset', async () => {
render(
<Trigger
popupVisible
popup={<span className="bamboo" />}
popupAlign={{
points: ['bc', 'tc'],
_experimental: {
dynamicInset: true,
},
}}
>
<div />
</Trigger>,
);

await awaitFakeTimer();

expect(document.querySelector('.rc-trigger-popup')).toHaveStyle({
bottom: `100px`,
});
});
});

0 comments on commit 2af861f

Please sign in to comment.