Skip to content

Commit

Permalink
feat: 优化selector组件
Browse files Browse the repository at this point in the history
  • Loading branch information
busy-mango committed Sep 24, 2024
1 parent 21ad371 commit 10038d1
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 114 deletions.
22 changes: 12 additions & 10 deletions src/components/widgets/control/models/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type React from 'react';
import type { FocusEvent } from 'react';
import type { HTMLMotionProps } from 'framer-motion';

import type { OmitOf } from '@busymango/utils';
Expand Down Expand Up @@ -28,19 +29,20 @@ export type ControlOption = {
title?: string;
label?: React.ReactNode;
disabled?: boolean;
};
icon?: React.ReactNode;
} & Pick<React.CSSProperties, 'color'>;

export interface InteractionProps {
ref: (node: HTMLElement | SVGElement | null) => void;
onBlur?(): void;
onFocus?(): void;
onClick?(): void;
onKeyUp?(): void;
onKeyDown?(): void;
onMouseDown?(): void;
onMouseMove?(): void;
onPointerDown?(): void;
onPointerEnter?(): void;
onBlur?(e: React.FocusEvent): void;
onFocus?(e: React.FocusEvent): void;
onClick?(e: React.MouseEvent): void;
onKeyUp?(e: React.KeyboardEvent): void;
onKeyDown?(e: React.KeyboardEvent): void;
onMouseDown?(e: React.MouseEvent): void;
onMouseMove?(e: React.MouseEvent): void;
onPointerDown?(e: React.UIEvent): void;
onPointerEnter?(e: React.UIEvent): void;
}

export type IControlVariant = 'filled' | 'standard' | 'bordered';
Expand Down
5 changes: 3 additions & 2 deletions src/components/widgets/popover/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ type MiddlewareOpts = {
export const iFill = (mode?: IPopoverProps['mode']) => {
switch (mode) {
case 'tip':
return 'var(--bg-color-float)';
return 'var(--bg-color-tip)';
case 'confirm':
return 'var(--bg-color-tip)';
default:
return 'var(--bg-color-card)';
}
Expand All @@ -36,7 +38,6 @@ export const iFloatingMaxSize = (
) => {
const { elements } = params;
const size = capitalize(mode);
console.log(params);
const availableSize = params[`available${size}`];
const scrollSize = elements.floating[`scroll${size}`];
const maxSize = ifnot(
Expand Down
15 changes: 10 additions & 5 deletions src/components/widgets/popover/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useControlState } from '../control';
import { useFloatingMotion } from './hooks/motion';
import { ARROW_HEIGHT, ARROW_RADIUS, iFill, middlewares } from './helpers';
import { useInterax } from './hooks';
import type { IPopoverProps, IPopoverRef } from './models';
import type { IPopoverProps, IPopoverRef, IPopoverState } from './models';

import * as styles from './index.scss';

Expand Down Expand Up @@ -61,12 +61,17 @@ export const IPopover = forwardRef<IPopoverRef, IPopoverProps>(

const interax = useInterax(context, { mode, events });

const states: IPopoverState = { open: context.open, placement };

return (
<Fragment>
{children?.({
ref: refs.setReference,
...interax.getReferenceProps(),
})}
{children?.(
{
ref: refs.setReference,
...interax.getReferenceProps(),
},
states
)}
{context.open && (
<FloatingPortal root={iFindElement(root)}>
<motion.div
Expand Down
4 changes: 3 additions & 1 deletion src/components/widgets/popover/models/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export type IPopoverRef = UseFloatingReturn['refs'];

export type IPopoverEvent = 'click' | 'focus' | 'hover';

export type IPopoverState = Pick<UseFloatingOptions, 'open' | 'placement'>;

export interface ApplyFloatingStyle {
(
params: MiddlewareState & {
Expand All @@ -33,5 +35,5 @@ export interface IPopoverProps
mode?: 'tip' | 'over' | 'confirm';
trigger?: IPopoverEvent | IPopoverEvent[];
onApplyFloatingStyle?: ApplyFloatingStyle;
children?: (props: InteractionProps) => React.ReactNode;
children?: (props: InteractionProps, state: IPopoverState) => React.ReactNode;
}
13 changes: 13 additions & 0 deletions src/components/widgets/selector/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { isNonEmptyString, isString } from '@busymango/is-esm';
import { ifnot } from '@busymango/utils';

import type { ControlOption } from '../../control';
import type { ISignType } from '../../sign';
import type { ISelectorState } from '../models';

Expand All @@ -16,3 +20,12 @@ export const iSignType = ({

return isShowClear ? 'cross' : iArrow;
};

export const iPredicate = (
{ title, label }: ControlOption,
keyword?: string
) => {
if (!isNonEmptyString(keyword)) return true;
const text = title ?? ifnot(isString(label) && label);
return text?.toLowerCase()?.includes(keyword?.toLowerCase()) ?? false;
};
31 changes: 8 additions & 23 deletions src/components/widgets/selector/hooks/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { useMemo } from 'react';
import { flushSync } from 'react-dom';

import {
isNonEmptyString,
isObject,
isString,
isTrue,
} from '@busymango/is-esm';
import { ifnot } from '@busymango/utils';
import { isObject, isTrue } from '@busymango/is-esm';
import type { FloatingContext, MiddlewareState } from '@floating-ui/react';
import {
autoUpdate,
Expand All @@ -25,6 +19,7 @@ import { size2px } from '@/utils';

import type { ControlOption } from '../../control';
import { estimateSize } from '../../scrollable';
import { iPredicate } from '../helpers';
import type { ISelectorPredicate, ISelectorProps } from '../models';

export const useIFloating = (params: {
Expand Down Expand Up @@ -118,24 +113,14 @@ export const useFilterOptions = (
const { filter, keyword } = params;

const predicate = useMemo<ISelectorPredicate | undefined>(() => {
if (isObject(filter)) {
return filter?.predicate;
}
if (isTrue(filter)) {
return ({ title, label }: ControlOption, keyword?: string) => {
if (!isNonEmptyString(keyword)) return true;
const text = title ?? ifnot(isString(label) && label);
return text?.toLowerCase()?.includes(keyword?.toLowerCase()) ?? false;
};
}
if (isTrue(filter)) return iPredicate;
if (isObject(filter)) return filter?.predicate;
}, [filter]);

return useMemo(() => {
if (predicate) {
return options?.filter((option) => {
return predicate(option, keyword);
});
}
return options;
if (!predicate) return options;
return options?.filter((option) => {
return predicate(option, keyword);
});
}, [predicate, keyword, options]);
};
132 changes: 68 additions & 64 deletions src/components/widgets/sign/line.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { forwardRef, useImperativeHandle, useRef } from 'react';
import { AnimatePresence, motion } from 'framer-motion';

import { IDollarPath } from './dollar';
Expand All @@ -6,68 +7,71 @@ import { iAnimateLine, initial, transition } from './helpers';
import { IMagnifierPath } from './magnifier';
import type { ISignLineProps } from './models';

export const ISignLine: React.FC<ISignLineProps> = ({
type,
rect,
ring,
style,
...others
}) => (
<motion.svg
fill="none"
height="1em"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={64}
style={{
...style,
transform: `scale(${ring || rect ? 1 : 1.325})`,
}}
version="1.1"
viewBox="0 0 1024 1024"
width="1em"
{...others}
>
<AnimatePresence>
{ring && (
<motion.circle
key="circle"
cx={512}
cy={512}
r={480}
transition={transition}
/>
)}
</AnimatePresence>
<AnimatePresence>
{rect && (
<motion.rect
key="rect"
height={960}
rx={256}
transition={transition}
width={960}
x={32}
y={32}
/>
)}
</AnimatePresence>
<AnimatePresence>
{iAnimateLine(type).map((animate, index) => (
<motion.path
key={index.toLocaleString()}
animate={animate}
exit={initial}
initial={initial}
transition={transition}
/>
))}
</AnimatePresence>
<AnimatePresence>
{type === 'dollar' && <IDollarPath key="dollar" />}
{type === 'helper' && <IHelperPath key="helper" />}
{type === 'magnifier' && <IMagnifierPath key="magnifier" />}
</AnimatePresence>
</motion.svg>
export const ISignLine = forwardRef<SVGSVGElement, ISignLineProps>(
function SignLine({ type, rect, ring, style, ...others }, iForwardRef) {
const ref = useRef<SVGSVGElement>(null);

useImperativeHandle(iForwardRef, () => ref.current!, [ref]);

return (
<motion.svg
ref={ref}
fill="none"
height="1em"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={64}
style={{
...style,
transform: `scale(${ring || rect ? 1 : 1.325})`,
}}
version="1.1"
viewBox="0 0 1024 1024"
width="1em"
{...others}
>
<AnimatePresence>
{ring && (
<motion.circle
key="circle"
cx={512}
cy={512}
r={480}
transition={transition}
/>
)}
</AnimatePresence>
<AnimatePresence>
{rect && (
<motion.rect
key="rect"
height={960}
rx={256}
transition={transition}
width={960}
x={32}
y={32}
/>
)}
</AnimatePresence>
<AnimatePresence>
{iAnimateLine(type).map((animate, index) => (
<motion.path
key={index.toLocaleString()}
animate={animate}
exit={initial}
initial={initial}
transition={transition}
/>
))}
</AnimatePresence>
<AnimatePresence>
{type === 'dollar' && <IDollarPath key="dollar" />}
{type === 'helper' && <IHelperPath key="helper" />}
{type === 'magnifier' && <IMagnifierPath key="magnifier" />}
</AnimatePresence>
</motion.svg>
);
}
);
1 change: 0 additions & 1 deletion src/components/widgets/snackbar/hooks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export const useSnackbars = create<ISnackbarStore & ISnackbarActions>(
);
},
emit: async (config: ISnackbarProps) => {
console.log(1);
const { snackbars: previous, max } = get();
const assert = ({ id }: ISnackbarProps) => id === config.id;
if (contains(previous, assert)) {
Expand Down
14 changes: 12 additions & 2 deletions src/components/widgets/wave/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ export const IWave: React.FC<IWaveProps> = (props) => {
({ clientWidth, clientHeight }) => {
scope.current.style.width = `${clientWidth}px`;
scope.current.style.height = `${clientHeight}px`;

console.log(clientWidth, clientHeight);
},
{ debounce: 10 * FRAME2MS }
);
Expand Down Expand Up @@ -98,3 +96,15 @@ export const IWaveWrap: ReactCFC<IWaveWrapProps> = ({
{children}
</span>
);

export const IWaveShell: React.FC<{
children: (ref: React.MutableRefObject<null>) => React.ReactNode;
}> = ({ children }) => {
const ref = useRef(null);
return (
<Fragment>
<IWave target={ref} />
{children(ref)}
</Fragment>
);
};
Loading

0 comments on commit 10038d1

Please sign in to comment.