Skip to content

Commit

Permalink
Fix a few type errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
mkrause committed Oct 12, 2024
1 parent 2f01563 commit b54b7b3
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/components/forms/context/Form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const Form = (props: FormProps) => {
const { unstyled = false, nestable, children, className, ...propsRest } = props;

const formId = React.useId();
const [wrapperRef, setWrapperRef] = React.useState<null | React.ElementRef<'div'>>(null);
const [wrapperRef, setWrapperRef] = React.useState<null | React.ComponentRef<'div'>>(null);

// Memoize to keep a stable reference
const context: FormContext = React.useMemo(() => ({ formId }), [formId]);
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/context/Form/FormOptics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const Form = (props: FormProps) => {
const { unstyled = false, nestable, children, className, ...propsRest } = props;

const formId = React.useId();
const [wrapperRef, setWrapperRef] = React.useState<null | React.ElementRef<'div'>>(null);
const [wrapperRef, setWrapperRef] = React.useState<null | React.ComponentRef<'div'>>(null);

// Memoize to keep a stable reference
const context: FormContext = React.useMemo(() => ({ formId }), [formId]);
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/controls/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const Select = Object.assign(
(props: SelectProps) => {
const { children, unstyled = false, searchable, ...propsRest } = props;

const selectedRef = React.useRef<React.ElementRef<'button'>>(null);
const selectedRef = React.useRef<React.ComponentRef<'button'>>(null);
const [selected, setSelected] = React.useState<null | OptionDef>(null);

const listRef = React.useRef([]);
Expand Down
8 changes: 4 additions & 4 deletions src/components/overlays/DropdownMenu/DropdownMenuProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ export const DropdownMenuProvider = Object.assign(
selectedRef.current?.focus(); // Return focus
},
close: () => { setIsOpen(false); },
}), [selected, selectedRef]);
}), [selected, setIsOpen, getItemProps]);

const renderAnchor = () => {
const anchorProps: AnchorRenderArgs['props'] = (userProps?: undefined | React.HTMLProps<Element>) => {
const userPropsRef: undefined | string | React.Ref<any> = userProps?.ref ?? undefined;
const userPropsRef: undefined | string | React.Ref<Element> = userProps?.ref ?? undefined;
if (typeof userPropsRef === 'string') {
// We can't merge refs if one of the refs is a string
console.error(`Failed to render DropdownMenuProvider, due to use of legacy string ref`);
Expand All @@ -112,7 +112,7 @@ export const DropdownMenuProvider = Object.assign(
return <span {...anchorProps()}>{children}</span>;
}
if (React.Children.count(children) === 1) {
return React.cloneElement(children, anchorProps(children.props));
return React.cloneElement(children, anchorProps(children.props as React.HTMLProps<Element>));
}

console.error(`Invalid children passed to DropdownMenuProvider, expected a render prop or single child element.`);
Expand All @@ -132,7 +132,7 @@ export const DropdownMenuProvider = Object.assign(
className: cx(propsRest.className),
})}
tabIndex={undefined}
ref={mergeRefs(refs.setFloating as any, propsRest.ref)}
ref={mergeRefs<HTMLUListElement>(refs.setFloating, propsRest.ref)}
data-placement={placementEffective}
>
{items}
Expand Down
6 changes: 3 additions & 3 deletions src/components/overlays/Tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const TooltipScroll: StoryObj<typeof Tooltip> = {
render: () => (
<Tooltip>
<p>
Lorem ipsum dolor sit amet, <a href="#">consectetur</a> adipiscing elit. Pellentesque eget sem ut neque lobortis pharetra nec vel quam. Etiam sem neque, gravida sed pharetra ut, vehicula quis lectus. Donec ac rhoncus purus. Proin ultricies augue vitae purus feugiat, in ultrices lorem aliquet. Donec eleifend ac dolor a auctor.
Lorem ipsum dolor sit amet, <a href="/" onClick={event => { event.preventDefault(); }}>consectetur</a> adipiscing elit. Pellentesque eget sem ut neque lobortis pharetra nec vel quam. Etiam sem neque, gravida sed pharetra ut, vehicula quis lectus. Donec ac rhoncus purus. Proin ultricies augue vitae purus feugiat, in ultrices lorem aliquet. Donec eleifend ac dolor a auctor.
</p>
<p>
Cras ac suscipit nibh. Fusce tincidunt iaculis dapibus. Vivamus sit amet neque eu velit tincidunt semper. Donec at magna aliquam mi consectetur imperdiet. Donec pretium placerat quam, in sodales purus porta vitae. Phasellus nisl justo, luctus vel mi vel, sollicitudin.
Expand All @@ -67,7 +67,7 @@ const TooltipNativeAnchoringControlled = () => {
// https://www.w3.org/TR/css-anchor-position-1/#implicit
const id = React.useId();
const anchorName = `--bk-tooltip-anchor-${CSS.escape(id)}`;
const refTooltip = React.useRef<React.ElementRef<typeof Tooltip>>(null);
const refTooltip = React.useRef<React.ComponentRef<typeof Tooltip>>(null);

return (
<>
Expand All @@ -76,7 +76,7 @@ const TooltipNativeAnchoringControlled = () => {
{/* @ts-ignore Anchor Positioning not yet supported. */}
<Tooltip ref={refTooltip} id={id} popover="manual" style={{ positionAnchor: anchorName }}>
This is a tooltip with a lot of text that gives more information about the element.
It has a <a href="#">link</a> you can focus.
It has a <a href="/" onClick={event => { event.preventDefault(); }}>link</a> you can focus.
</Tooltip>
<Button type="button" popoverTarget={id} variant="primary" label="Hover over me"
// @ts-ignore Anchor Positioning not yet supported.
Expand Down
6 changes: 3 additions & 3 deletions src/components/overlays/Tooltip/TooltipProvider.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ export const TooltipWithFocus: Story = {
};

const TooltipWithDrag = () => {
const boundaryRef = React.useRef<React.ElementRef<'div'>>(null);
const boundaryRef = React.useRef<React.ComponentRef<'div'>>(null);
const [boundaryRendered, setBoundaryRendered] = React.useState(false);

React.useEffect(() => {
if (boundaryRef.current && !boundaryRendered) { setBoundaryRendered(true); }
}, [boundaryRef.current]);
}, [boundaryRendered]);

return (
<div ref={boundaryRef} style={{ minHeight: 400, display: 'grid', placeContent: 'center' }}>
{boundaryRef.current &&
<Draggable>
<Draggable<HTMLButtonElement>>
{({ targetRef }) =>
<TooltipProvider
tooltip="The position of this tooltip will update to stay in view as it gets dragged towards
Expand Down
13 changes: 6 additions & 7 deletions src/components/overlays/Tooltip/TooltipProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,10 @@ export const TooltipProvider = (props: TooltipProviderProps) => {
...tooltipProps
} = props;

const arrowRef = React.useRef(null);
const arrowRef = React.useRef<HTMLElement>(null);

const {
context,
isOpen,
isMounted,
refs,
floatingStyles,
Expand All @@ -70,7 +69,7 @@ export const TooltipProvider = (props: TooltipProviderProps) => {
offset: 6,
enablePreciseTracking,
boundary,
arrowRef,
...(arrowRef.current ? { arrowRef: arrowRef as React.RefObject<HTMLElement> } : {}),
});
const arrow = usePopoverArrow({ context });

Expand All @@ -81,7 +80,7 @@ export const TooltipProvider = (props: TooltipProviderProps) => {
} else {
onTooltipDeactivated?.();
}
}, [isMounted]);
}, [isMounted, onTooltipActivated, onTooltipDeactivated]);

const renderTooltip = () => {
if (!isMounted) { return null; }
Expand All @@ -93,7 +92,7 @@ export const TooltipProvider = (props: TooltipProviderProps) => {
return (
<Tooltip
{...floatingProps}
ref={mergeRefs(refs.setFloating as any, tooltipProps.ref)}
ref={mergeRefs<HTMLDivElement>(refs.setFloating, tooltipProps.ref)}
className={cx(
floatingProps.className as ClassNameArgument,
{ [TooltipClassNames['bk-tooltip--arrow-top']]: arrow?.side === 'top' },
Expand All @@ -120,7 +119,7 @@ export const TooltipProvider = (props: TooltipProviderProps) => {

const renderAnchor = () => {
const renderPropArg: GetReferenceProps = (userProps?: undefined | React.HTMLProps<Element>) => {
const userPropsRef: undefined | string | React.Ref<any> = userProps?.ref ?? undefined;
const userPropsRef: undefined | string | React.Ref<Element> = userProps?.ref ?? undefined;
if (typeof userPropsRef === 'string') {
// We can't merge refs if one of the refs is a string
console.error(`Failed to render Tooltip, due to use of legacy string ref`);
Expand All @@ -143,7 +142,7 @@ export const TooltipProvider = (props: TooltipProviderProps) => {
return <span {...renderPropArg()}>{children}</span>;
}
if (React.Children.count(children) === 1) {
return React.cloneElement(children, renderPropArg(children.props));
return React.cloneElement(children, renderPropArg(children.props as React.HTMLProps<Element>));
}

console.error(`Invalid children passed to TooltipContainer, expected a render prop or single child element.`);
Expand Down
23 changes: 14 additions & 9 deletions src/util/drag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,25 @@ export type UseDraggableProps = {
viewport?: boolean,
rectLimits?: { left: number, right: number, top: number, bottom: number },
};
export type UseDraggableResult = {
targetRef: React.Ref<null | HTMLElement>,
handleRef: React.Ref<null | HTMLElement>,
export type UseDraggableResult<T extends HTMLElement, H extends HTMLElement> = {
targetRef: React.Ref<T>,
handleRef: React.Ref<H>,
getTargetProps: () => Record<string, unknown>,
dragging: boolean,
delta: Delta,
resetState: () => void,
};
export const useDraggable = (props: UseDraggableProps): UseDraggableResult => {
export const useDraggable = <T extends HTMLElement = HTMLElement, H extends HTMLElement = HTMLElement>(
props: UseDraggableProps,
): UseDraggableResult<T, H> => {
const {
controlStyle = true,
viewport = false,
rectLimits,
} = props;

const targetRef = React.useRef<HTMLElement>(null);
const handleRef = React.useRef<HTMLElement>(null);
const targetRef = React.useRef<T>(null);
const handleRef = React.useRef<H>(null);
const [dragging, setDragging] = React.useState<boolean>(false);
const [prev, setPrev] = React.useState({ x: 0, y: 0 });
const [delta, setDelta] = React.useState({ x: 0, y: 0 });
Expand Down Expand Up @@ -184,9 +186,12 @@ export const useDraggable = (props: UseDraggableProps): UseDraggableResult => {
return { targetRef, handleRef, getTargetProps, dragging, delta, resetState };
};

export type DraggableProps = {
children: (result: UseDraggableResult) => React.ReactNode,
export type DraggableProps<T extends HTMLElement, H extends HTMLElement> = {
children: (result: UseDraggableResult<T, H>) => React.ReactNode,
};
export const Draggable = ({ children, ...rest }: DraggableProps) => {
export const Draggable = <T extends HTMLElement = HTMLElement, H extends HTMLElement = HTMLElement>({
children,
...rest
}: DraggableProps<T, H>) => {
return children(useDraggable(rest));
};

0 comments on commit b54b7b3

Please sign in to comment.