Skip to content

Commit

Permalink
feat(ui): fab add backtop support
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Sep 15, 2022
1 parent 308bdf0 commit 4c36143
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 38 deletions.
3 changes: 3 additions & 0 deletions packages/ui/src/components/fab/Fab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getClassName } from '@react-devui/utils';

import { usePrefixConfig, useComponentConfig, useDValue } from '../../hooks';
import { registerComponentMate } from '../../utils';
import { DFabBacktop } from './FabBacktop';
import { DFabButton } from './FabButton';

export interface DFabProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
Expand All @@ -20,6 +21,7 @@ const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DFab' as con
export const DFab: {
(props: DFabProps): JSX.Element | null;
Button: typeof DFabButton;
Backtop: typeof DFabBacktop;
} = (props) => {
const {
children,
Expand Down Expand Up @@ -75,3 +77,4 @@ export const DFab: {
};

DFab.Button = DFabButton;
DFab.Backtop = DFabBacktop;
102 changes: 102 additions & 0 deletions packages/ui/src/components/fab/FabBacktop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { DTransitionState } from '../_transition';
import type { DFabButtonProps } from './FabButton';
import type { DElementSelector } from '@react-devui/hooks/useElement';

import React, { useRef, useState } from 'react';

import { useElement, useEvent, useIsomorphicLayoutEffect, useResize } from '@react-devui/hooks';
import { VerticalAlignTopOutlined } from '@react-devui/icons';
import { checkNodeExist, scrollTo } from '@react-devui/utils';

import { useComponentConfig, useLayout } from '../../hooks';
import { registerComponentMate, TTANSITION_DURING_BASE } from '../../utils';
import { DTransition } from '../_transition';
import { DFabButton } from './FabButton';

export interface DFabBacktopProps extends DFabButtonProps {
dPage?: DElementSelector;
dDistance?: number;
dScrollBehavior?: 'instant' | 'smooth';
}

const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DFab.Backtop' as const });
function FabBacktop(props: DFabBacktopProps, ref: React.ForwardedRef<HTMLButtonElement>): JSX.Element | null {
const {
children,
dPage,
dDistance = 400,
dScrollBehavior = 'instant',

...restProps
} = useComponentConfig(COMPONENT_NAME, props);

//#region Context
const { dScrollEl, dResizeEl } = useLayout();
//#endregion

const dataRef = useRef<{
clearTid?: () => void;
}>({});

const pageEl = useElement(dPage ?? dScrollEl);
const resizeEl = useElement(dResizeEl);

const [visible, setVisible] = useState(false);

const transitionStyles: Partial<Record<DTransitionState, React.CSSProperties>> = {
enter: { opacity: 0 },
entering: {
transition: ['opacity'].map((attr) => `${attr} ${TTANSITION_DURING_BASE}ms linear`).join(', '),
},
leaving: {
opacity: 0,
transition: ['opacity'].map((attr) => `${attr} ${TTANSITION_DURING_BASE}ms linear`).join(', '),
},
leaved: { display: 'none' },
};

const updateBackTop = () => {
if (!pageEl) {
return;
}

setVisible(pageEl.scrollTop >= dDistance);
};
useIsomorphicLayoutEffect(() => {
updateBackTop();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useResize(resizeEl, updateBackTop);
useEvent(pageEl, 'scroll', updateBackTop, { passive: true });

return (
<DTransition dIn={visible} dDuring={TTANSITION_DURING_BASE}>
{(state) => (
<DFabButton
{...restProps}
ref={ref}
style={{
...restProps.style,
...transitionStyles[state],
}}
onClick={(e) => {
restProps.onClick?.(e);

if (pageEl) {
dataRef.current.clearTid?.();
dataRef.current.clearTid = scrollTo(pageEl, {
top: 0,
behavior: dScrollBehavior,
});
}
}}
>
{checkNodeExist(children) ? children : <VerticalAlignTopOutlined />}
</DFabButton>
)}
</DTransition>
);
}

export const DFabBacktop = React.forwardRef(FabBacktop);
61 changes: 61 additions & 0 deletions packages/ui/src/components/fab/demos/3.Loading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
title:
en-US: Loading
zh-CN: 加载中
---

# en-US

Add the `dLoading` attribute to make the button in the loading state.

# zh-CN

添加 `dLoading` 属性即可让按钮处于加载状态。

```tsx
import { useState, useRef } from 'react';

import { useAsync, useImmer } from '@react-devui/hooks';
import { CaretRightOutlined, DeleteOutlined } from '@react-devui/icons';
import { DFab } from '@react-devui/ui';

export default function Demo() {
const dataRef = useRef({});
const async = useAsync();

const [loading, setLoading] = useImmer(false);
const [expand, setExpand] = useImmer(false);

return (
<DFab
dList={[
{
placement: 'right',
actions: [
<DFab.Button
dTheme="danger"
dVariant="circle"
dLoading={loading}
onClick={() => {
setLoading(true);
dataRef.current.clearTid?.();
dataRef.current.clearTid = async.setTimeout(() => {
setLoading(false);
setExpand(false);
}, 1000);
}}
>
<DeleteOutlined />
</DFab.Button>,
],
},
]}
dExpand={expand}
>
<DFab.Button dVariant="circle" onClick={() => setExpand((draft) => !draft)}>
<CaretRightOutlined />
</DFab.Button>
</DFab>
);
}
```
25 changes: 25 additions & 0 deletions packages/ui/src/components/fab/demos/4.Backtop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title:
en-US: Backtop
zh-CN: 回到顶部
---

# en-US

`DFab.Backtop` component provided.

# zh-CN

提供了 `DFab.Backtop` 组件。

```tsx
import { DFab } from '@react-devui/ui';

export default function Demo() {
return (
<DFab style={{ position: 'fixed', right: 100, bottom: 40 }}>
<DFab.Backtop dVariant="circle" />
</DFab>
);
}
```
1 change: 1 addition & 0 deletions packages/ui/src/components/fab/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './Fab';
export * from './FabButton';
export * from './FabBacktop';
4 changes: 2 additions & 2 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export { DDropdown } from './dropdown';
export type { DEmptyProps } from './empty';
export { DEmpty } from './empty';

export type { DFabProps, DFabButtonProps } from './fab';
export { DFab, DFabButton } from './fab';
export type { DFabProps, DFabButtonProps, DFabBacktopProps } from './fab';
export { DFab, DFabButton, DFabBacktop } from './fab';

export type { DFormProps, DFormItemProps, DFormGroupProps } from './form';
export { DForm, useForm, FormControl, FormGroup, Validators } from './form';
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/hooks/d-config/contex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
DEmptyProps,
DFabProps,
DFabButtonProps,
DFabBacktopProps,
DFormProps,
DFormGroupProps,
DFormItemProps,
Expand Down Expand Up @@ -113,6 +114,7 @@ export type DComponentConfig = {
DEmpty: DEmptyProps;
DFab: DFabProps;
'DFab.Button': DFabButtonProps;
'DFab.Backtop': DFabBacktopProps;
DForm: DFormProps;
'DForm.Group': DFormGroupProps;
'DForm.Item': DFormItemProps<any>;
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ $popover-space: 10px;
/** component **/
--#{$variable-prefix}avatar-background-color: #bdbdbd;
--#{$variable-prefix}breadcrumb-text-color: #b1b1b1;
--#{$variable-prefix}fab-shadow: 0 3px 5px -1px rgb(0 0 0 / 20%), 0 6px 10px 0 rgb(0 0 0 / 14%), 0 1px 14px 0 rgb(0 0 0 / 12%);
--#{$variable-prefix}mask-background-color: rgb(0 0 0 / 20%);
--#{$variable-prefix}skeleton-background-color-wave: rgb(255 255 255 / 50%);
--#{$variable-prefix}switch-background-color: #d4d6d9;
Expand Down
Loading

0 comments on commit 4c36143

Please sign in to comment.