docs,api-ref: added search filters (#4830)
* initial implementation of search modal * added hit and search suggestions * added support for multiple indices * updated sample env * added close when click outside dropdown * test for mobile * added mobile design * added shortcut * dark mode fixes * added search to docs * added plugins filter * added React import * moved filters to configurations * handled error on page load * change suggestion text * removed hits limit * handle select all * open link in current tab * change highlight colors * added support for shortcuts + auto focus * change header and footer * redesigned search ui
This commit is contained in:
@@ -2,11 +2,12 @@ import clsx from "clsx"
|
||||
import Button, { ButtonProps } from "../../Button"
|
||||
|
||||
type ModalFooterProps = {
|
||||
actions: ButtonProps[]
|
||||
actions?: ButtonProps[]
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
const ModalFooter = ({ actions, className }: ModalFooterProps) => {
|
||||
const ModalFooter = ({ actions, children, className }: ModalFooterProps) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
@@ -16,9 +17,10 @@ const ModalFooter = ({ actions, className }: ModalFooterProps) => {
|
||||
className
|
||||
)}
|
||||
>
|
||||
{actions.map((action, index) => (
|
||||
{actions?.map((action, index) => (
|
||||
<Button {...action} key={index} />
|
||||
))}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import clsx from "clsx"
|
||||
import { useModal } from "../../../providers/modal"
|
||||
import IconXMark from "../../Icons/XMark"
|
||||
import Button from "../../Button"
|
||||
|
||||
type ModalHeaderProps = {
|
||||
title?: string
|
||||
@@ -23,9 +24,13 @@ const ModalHeader = ({ title }: ModalHeaderProps) => {
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
<button className="btn-clear cursor-pointer" onClick={() => closeModal()}>
|
||||
<Button
|
||||
variant="clear"
|
||||
className="cursor-pointer"
|
||||
onClick={() => closeModal()}
|
||||
>
|
||||
<IconXMark />
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,70 +1,117 @@
|
||||
import clsx from "clsx"
|
||||
import React, { useRef } from "react"
|
||||
import React, { forwardRef, useCallback, useEffect, useRef } from "react"
|
||||
import { ButtonProps } from "../Button"
|
||||
import { useModal } from "../../providers/modal"
|
||||
import ModalHeader from "./Header"
|
||||
import ModalFooter from "./Footer"
|
||||
import useKeyboardShortcut from "../../hooks/use-keyboard-shortcut"
|
||||
|
||||
export type ModalProps = {
|
||||
className?: string
|
||||
title?: string
|
||||
actions?: ButtonProps[]
|
||||
modalContainerClassName?: string
|
||||
contentClassName?: string
|
||||
} & React.DetailedHTMLProps<
|
||||
React.DialogHTMLAttributes<HTMLDialogElement>,
|
||||
HTMLDialogElement
|
||||
>
|
||||
onClose?: React.ReactEventHandler<HTMLDialogElement>
|
||||
open?: boolean
|
||||
footerContent?: React.ReactNode
|
||||
} & Omit<React.ComponentProps<"dialog">, "ref">
|
||||
|
||||
const Modal: React.FC<ModalProps> = ({
|
||||
className,
|
||||
title,
|
||||
actions,
|
||||
children,
|
||||
contentClassName,
|
||||
...props
|
||||
}) => {
|
||||
const Modal = forwardRef<HTMLDialogElement, ModalProps>(function Modal(
|
||||
{
|
||||
className,
|
||||
title,
|
||||
actions,
|
||||
children,
|
||||
contentClassName,
|
||||
modalContainerClassName,
|
||||
onClose,
|
||||
open = true,
|
||||
footerContent,
|
||||
...props
|
||||
},
|
||||
passedRef
|
||||
) {
|
||||
const { closeModal } = useModal()
|
||||
const dialogRef = useRef<HTMLDialogElement>(null)
|
||||
const ref = useRef<HTMLDialogElement | null>(null)
|
||||
|
||||
const setRefs = useCallback(
|
||||
(node: HTMLDialogElement) => {
|
||||
// Ref's from useRef needs to have the node assigned to `current`
|
||||
ref.current = node
|
||||
if (typeof passedRef === "function") {
|
||||
passedRef(node)
|
||||
} else if (passedRef && "current" in passedRef) {
|
||||
passedRef.current = node
|
||||
}
|
||||
},
|
||||
[passedRef]
|
||||
)
|
||||
|
||||
useKeyboardShortcut({
|
||||
metakey: false,
|
||||
checkEditing: false,
|
||||
shortcutKeys: ["escape"],
|
||||
action: () => {
|
||||
if (open) {
|
||||
ref.current?.close()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLDialogElement, MouseEvent>) => {
|
||||
// close modal when the user clicks outside the content
|
||||
if (e.target === dialogRef.current) {
|
||||
if (e.target === ref.current) {
|
||||
closeModal()
|
||||
onClose?.(e)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = (e: React.SyntheticEvent<HTMLDialogElement, Event>) => {
|
||||
onClose?.(e)
|
||||
closeModal()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
document.body.setAttribute("data-modal", "opened")
|
||||
} else {
|
||||
document.body.removeAttribute("data-modal")
|
||||
}
|
||||
}, [open])
|
||||
|
||||
return (
|
||||
<dialog
|
||||
{...props}
|
||||
className={clsx(
|
||||
"fixed top-0 left-0 flex h-screen w-screen items-center justify-center",
|
||||
"z-[500] bg-transparent",
|
||||
"bg-medusa-bg-overlay dark:bg-medusa-bg-overlay-dark z-[500]",
|
||||
"hidden open:flex",
|
||||
className
|
||||
)}
|
||||
onClick={handleClick}
|
||||
ref={dialogRef}
|
||||
ref={setRefs}
|
||||
onClose={handleClose}
|
||||
open={open}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"bg-medusa-bg-base dark:bg-medusa-bg-base-dark rounded-sm",
|
||||
"border-medusa-border-base dark:border-medusa-border-base-dark border border-solid",
|
||||
"shadow-modal dark:shadow-modal-dark",
|
||||
"w-[90%] md:w-[75%] lg:w-[560px]"
|
||||
"w-[90%] md:h-auto md:w-[75%] lg:w-[560px]",
|
||||
modalContainerClassName
|
||||
)}
|
||||
>
|
||||
<ModalHeader title={title} />
|
||||
<div
|
||||
className={clsx(
|
||||
"overflow-auto py-1.5 px-2 lg:min-h-[400px]",
|
||||
contentClassName
|
||||
)}
|
||||
>
|
||||
{title && <ModalHeader title={title} />}
|
||||
<div className={clsx("overflow-auto py-1.5 px-2", contentClassName)}>
|
||||
{children}
|
||||
</div>
|
||||
{actions && actions?.length > 0 && <ModalFooter actions={actions} />}
|
||||
{footerContent && <ModalFooter>{footerContent}</ModalFooter>}
|
||||
</div>
|
||||
</dialog>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default Modal
|
||||
|
||||
Reference in New Issue
Block a user