Skip to content

Commit

Permalink
Merge pull request #268 from anubra266/fix/utils
Browse files Browse the repository at this point in the history
Remove utils dependency
  • Loading branch information
Kysluss authored Oct 10, 2024
2 parents b0c52a6 + b0feb24 commit 9543b2e
Show file tree
Hide file tree
Showing 13 changed files with 308 additions and 116 deletions.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
},
"peerDependencies": {
"@chakra-ui/react": "^2.5.5",
"@chakra-ui/react-utils": "^2.0.5",
"@chakra-ui/utils": "^2.0.8",
"@emotion/react": "^11.10.0",
"@emotion/styled": "^11.10.0",
"framer-motion": ">7.6.14",
Expand Down Expand Up @@ -92,4 +90,4 @@
"vite-plugin-linter": "^3.0.0",
"vite-tsconfig-paths": "^5.0.1"
}
}
}
35 changes: 29 additions & 6 deletions src/autocomplete-context.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
import { createContext } from "@chakra-ui/react-utils";
import * as React from "react";
import { UseAutoCompleteReturn } from "./types";

export const [AutoCompleteProvider, useAutoCompleteContext] = createContext<
UseAutoCompleteReturn
>({
name: "AutoCompleteContext",
errorMessage:
"useAutoCompleteContext: `context` is undefined. Seems you forgot to wrap all autoomplete components within `<AutoComplete />`",
});
>();

type CreateContextReturn<T> = [React.Provider<T>, () => T, React.Context<T>];

export function createContext<ContextType>() {
const Context = React.createContext<ContextType | undefined>(undefined);

Context.displayName = "AutoCompleteContext";

function useContext() {
const context = React.useContext(Context);
const errorMessage =
"useAutoCompleteContext: `context` is undefined. Seems you forgot to wrap all autoomplete components within `<AutoComplete />`";

if (!context) {
const error = new Error(errorMessage);
error.name = "ContextError";
Error.captureStackTrace?.(error, useContext);
throw error;
}

return context;
}

return [Context.Provider, useContext, Context] as CreateContextReturn<
ContextType
>;
}
4 changes: 2 additions & 2 deletions src/autocomplete-creatable.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Flex, FlexProps } from "@chakra-ui/react";
import { MaybeRenderProp } from "@chakra-ui/react-utils";
import { isEmpty, runIfFn } from "@chakra-ui/utils";
import { MaybeRenderProp } from "./types";
import { isEmpty, runIfFn } from "./utils";

import React from "react";

Expand Down
2 changes: 1 addition & 1 deletion src/autocomplete-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
FlexProps,
forwardRef,
} from "@chakra-ui/react";
import { omit } from "@chakra-ui/utils";
import { omit } from "./utils";
import React from "react";
import { useAutoCompleteContext } from "./autocomplete-context";

Expand Down
75 changes: 46 additions & 29 deletions src/autocomplete-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,42 @@ import {
forwardRef,
Input,
InputProps,
InputGroup,
InputRightElement,
InputGroup,
InputRightElement,
Spinner,
SystemStyleObject,
useMergeRefs,
useMultiStyleConfig,
Wrap,
WrapItem,
PopoverAnchor
WrapItem,
PopoverAnchor,
} from "@chakra-ui/react";
import { runIfFn } from "@chakra-ui/utils";
import { MaybeRenderProp } from "@chakra-ui/react-utils";
import { runIfFn } from "./utils";
import React, { useEffect } from "react";

import { useAutoCompleteContext } from "./autocomplete-context";
import { UseAutoCompleteReturn } from "./types";
import { MaybeRenderProp, UseAutoCompleteReturn } from "./types";

export interface AutoCompleteInputProps extends Omit<InputProps, "children"> {
children?: MaybeRenderProp<{ tags: UseAutoCompleteReturn["tags"] }>;
wrapStyles?: SystemStyleObject;
hidePlaceholder?: boolean;
loadingIcon?: React.ReactNode
loadingIcon?: React.ReactNode;
}

const AutoCompleteInputComponent = forwardRef(
(props, forwardedRef) => {
const { isLoading } = useAutoCompleteContext();
const { loadingIcon, ...inputProps } = props;

return <InputGroup>
<Input {...inputProps} ref={forwardedRef} />
{ isLoading && <InputRightElement>
{ loadingIcon || <Spinner /> }
</InputRightElement> }
</InputGroup>;
}
)
const AutoCompleteInputComponent = forwardRef((props, forwardedRef) => {
const { isLoading } = useAutoCompleteContext();
const { loadingIcon, ...inputProps } = props;

return (
<InputGroup>
<Input {...inputProps} ref={forwardedRef} />
{isLoading && (
<InputRightElement>{loadingIcon || <Spinner />}</InputRightElement>
)}
</InputGroup>
);
});

export const AutoCompleteInput = forwardRef<AutoCompleteInputProps, "input">(
(props, forwardedRef) => {
Expand All @@ -47,9 +46,9 @@ export const AutoCompleteInput = forwardRef<AutoCompleteInputProps, "input">(
inputRef,
getInputProps,
tags,
setQuery,
value,
itemList
setQuery,
value,
itemList,
} = useAutoCompleteContext();

// const ref = useMergeRefs(forwardedRef, inputRef);
Expand All @@ -64,7 +63,10 @@ export const AutoCompleteInput = forwardRef<AutoCompleteInputProps, "input">(
const { value: inputValue } = rest;

useEffect(() => {
if(value !== undefined && (typeof value === 'string' || value instanceof String)) {
if (
value !== undefined &&
(typeof value === "string" || value instanceof String)
) {
const item = itemList.find(l => l.value === value);

const newQuery = item === undefined ? value : item.label;
Expand All @@ -74,7 +76,10 @@ export const AutoCompleteInput = forwardRef<AutoCompleteInputProps, "input">(
}, [value]);

useEffect(() => {
if(inputValue !== undefined && (typeof inputValue === 'string' || inputValue instanceof String)) {
if (
inputValue !== undefined &&
(typeof inputValue === "string" || inputValue instanceof String)
) {
setQuery(inputValue);
}
}, [inputValue]);
Expand All @@ -97,17 +102,29 @@ export const AutoCompleteInput = forwardRef<AutoCompleteInputProps, "input">(
}

const simpleInput = (
<AutoCompleteInputComponent isInvalid={isInvalid} {...(inputProps as any)} ref={ref} />
<AutoCompleteInputComponent
isInvalid={isInvalid}
{...(inputProps as any)}
ref={ref}
/>
);

const multipleInput = (
<Wrap aria-invalid={isInvalid} {...wrapperProps} ref={wrapperRef}>
{children}
<WrapItem as={AutoCompleteInputComponent} {...(inputProps as any)} ref={ref} />
<WrapItem
as={AutoCompleteInputComponent}
{...(inputProps as any)}
ref={ref}
/>
</Wrap>
);

return <PopoverAnchor>{autoCompleteProps.multiple ? multipleInput : simpleInput}</PopoverAnchor>;
return (
<PopoverAnchor>
{autoCompleteProps.multiple ? multipleInput : simpleInput}
</PopoverAnchor>
);
}
);

Expand Down
2 changes: 1 addition & 1 deletion src/autocomplete-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
forwardRef,
useMergeRefs,
} from "@chakra-ui/react";
import { isUndefined, omit } from "@chakra-ui/utils";
import { isUndefined, omit } from "./utils";
import React, { useEffect, useRef } from "react";

import { useAutoCompleteContext } from "./autocomplete-context";
Expand Down
2 changes: 1 addition & 1 deletion src/autocomplete-tag.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { WrapItem } from "@chakra-ui/layout";
import { Tag, TagCloseButton, TagLabel, TagProps } from "@chakra-ui/tag";
import { runIfFn } from "@chakra-ui/utils";
import { runIfFn } from "./utils";
import React, { memo } from "react";

type AutoCompleteTagProps = {
Expand Down
14 changes: 7 additions & 7 deletions src/autocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, { useImperativeHandle } from "react";
import { MaybeRenderProp } from "@chakra-ui/react-utils";

import { AutoCompleteProvider } from "./autocomplete-context";
import { useAutoComplete } from "./use-autocomplete";
import { chakra, forwardRef, Popover } from "@chakra-ui/react";
import { AutoCompleteRefMethods, UseAutoCompleteProps } from "./types";
import {
AutoCompleteRefMethods,
UseAutoCompleteProps,
MaybeRenderProp,
} from "./types";

export type AutoCompleteChildProps = {
isOpen: boolean;
Expand All @@ -24,7 +27,7 @@ export const AutoComplete = forwardRef<AutoCompleteProps, "div">(
isOpen,
onClose,
onOpen,
placement,
placement,
resetItems,
removeItem,
} = context;
Expand All @@ -48,10 +51,7 @@ export const AutoComplete = forwardRef<AutoCompleteProps, "div">(
closeOnBlur={true}
matchWidth={matchWidth}
>
<chakra.div
w="full"
ref={ref}
>
<chakra.div w="full" ref={ref}>
{children}
</chakra.div>
</Popover>
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/group.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isDefined, runIfFn } from "@chakra-ui/utils";
import { isDefined, runIfFn } from "../utils";
import { getChildDeep } from "react-nanny";
import { ReactNode } from "react";
import { getDefItemValue } from "./items";
Expand Down
7 changes: 5 additions & 2 deletions src/helpers/items.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { getChildrenDeep } from "react-nanny";
import { pick, isDefined, isEmpty } from "@chakra-ui/utils";
import { pick, isDefined, isEmpty } from "../utils";
import { ReactNode } from "react";
import { FlexProps } from "@chakra-ui/react";
import { fuzzyScore } from "./fuzzySearch";
import { Item } from "../types";
import { AutoCompleteItemProps } from "../autocomplete-item";

export const getDefItemValue = (item: AutoCompleteItemProps["value"]) =>
(typeof item === "string" || typeof item === "number" ? item : item[Object.keys(item)[0]])?.toString();
(typeof item === "string" || typeof item === "number"
? item
: item[Object.keys(item)[0]]
)?.toString();

export const setEmphasis = (children: any, query: string) => {
if (typeof children !== "string" || isEmpty(query)) {
Expand Down
15 changes: 10 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ import {
InputProps,
PlacementWithLogical,
SystemStyleObject,
WrapProps
WrapProps,
} from "@chakra-ui/react";
import { MaybeRenderProp } from "@chakra-ui/react-utils";
import React, { Dispatch, SetStateAction } from "react";

import { AutoCompleteProps } from "./autocomplete";
import { AutoCompleteGroupProps } from "./autocomplete-group";
import { AutoCompleteInputProps } from "./autocomplete-input";
import { AutoCompleteItemProps } from "./autocomplete-item";

export type Dict<T = any> = Record<string, T>;

export type MaybeRenderProp<P> =
| React.ReactNode
| ((props: P) => React.ReactNode);

export interface Item {
value: any;
label?: any;
Expand All @@ -28,7 +33,7 @@ export interface Item {
export type UseAutoCompleteProps = Partial<{
closeOnBlur: boolean;
closeOnSelect: boolean;
prefocusFirstItem: boolean
prefocusFirstItem: boolean;
creatable: boolean;
defaultEmptyStateProps: FlexProps;
defaultIsOpen: boolean;
Expand All @@ -44,7 +49,7 @@ export type UseAutoCompleteProps = Partial<{
) => boolean;
focusInputOnSelect: boolean;
freeSolo: boolean;
isLoading: boolean,
isLoading: boolean;
isReadOnly: boolean;
listAllValuesOnFocus: boolean;
matchWidth: boolean;
Expand Down Expand Up @@ -124,7 +129,7 @@ export type GroupReturnProps = {
export type UseAutoCompleteReturn = {
autoCompleteProps: AutoCompleteProps;
children: React.ReactNode;
defaultEmptyStateProps: FlexProps,
defaultEmptyStateProps: FlexProps;
filteredList: Item[];
filteredResults: Item[];
focusedValue: Item["value"];
Expand Down
Loading

0 comments on commit 9543b2e

Please sign in to comment.