-
+
+
diff --git a/www/api-reference/components/Search/EmptyQueryBoundary/index.tsx b/www/api-reference/components/Search/EmptyQueryBoundary/index.tsx
new file mode 100644
index 0000000000..0f9b78642c
--- /dev/null
+++ b/www/api-reference/components/Search/EmptyQueryBoundary/index.tsx
@@ -0,0 +1,21 @@
+import { useInstantSearch } from "react-instantsearch"
+
+type SearchEmptyQueryBoundaryProps = {
+ children: React.ReactNode
+ fallback: React.ReactNode
+}
+
+const SearchEmptyQueryBoundary = ({
+ children,
+ fallback,
+}: SearchEmptyQueryBoundaryProps) => {
+ const { indexUiState } = useInstantSearch()
+
+ if (!indexUiState.query) {
+ return fallback
+ }
+
+ return children
+}
+
+export default SearchEmptyQueryBoundary
diff --git a/www/api-reference/components/Search/Hits/GroupName/index.tsx b/www/api-reference/components/Search/Hits/GroupName/index.tsx
new file mode 100644
index 0000000000..a325f9e9a6
--- /dev/null
+++ b/www/api-reference/components/Search/Hits/GroupName/index.tsx
@@ -0,0 +1,21 @@
+import clsx from "clsx"
+
+type SearchHitGroupNameProps = {
+ name: string
+}
+
+const SearchHitGroupName = ({ name }: SearchHitGroupNameProps) => {
+ return (
+
+ {name}
+
+ )
+}
+
+export default SearchHitGroupName
diff --git a/www/api-reference/components/Search/Hits/index.tsx b/www/api-reference/components/Search/Hits/index.tsx
new file mode 100644
index 0000000000..4d4acd4d6d
--- /dev/null
+++ b/www/api-reference/components/Search/Hits/index.tsx
@@ -0,0 +1,209 @@
+import clsx from "clsx"
+import Link from "next/link"
+import { Fragment, useEffect, useMemo, useState } from "react"
+import {
+ Configure,
+ ConfigureProps,
+ Index,
+ Snippet,
+ useHits,
+ useInstantSearch,
+} from "react-instantsearch"
+import SearchNoResult from "../NoResults"
+import SearchHitGroupName from "./GroupName"
+import getBaseUrl from "../../../utils/get-base-url"
+import { useSearch } from "../../../providers/search"
+
+type Hierarchy = "lvl0" | "lvl1" | "lvl2" | "lvl3" | "lvl4" | "lvl5"
+
+export type HitType = {
+ hierarchy: {
+ lvl0: string | null
+ lvl1: string | null
+ lvl2: string | null
+ lvl3: string | null
+ lvl4: string | null
+ lvl5: string | null
+ }
+ _tags: string[]
+ url: string
+ type?: "lvl1" | "lvl2" | "lvl3" | "lvl4" | "lvl5" | "content"
+ content?: string
+ __position: number
+ __queryID?: string
+ objectID: string
+}
+
+type GroupedHitType = {
+ [k: string]: HitType[]
+}
+
+type SearchHitWrapperProps = {
+ configureProps: ConfigureProps
+}
+
+type IndexResults = {
+ [k: string]: boolean
+}
+
+const SearchHitsWrapper = ({ configureProps }: SearchHitWrapperProps) => {
+ const { status } = useInstantSearch()
+ const indices = useMemo(
+ () => [
+ process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME || "temp",
+ process.env.NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME || "temp",
+ ],
+ []
+ )
+ const [hasNoResults, setHashNoResults] = useState
({
+ [indices[0]]: false,
+ [indices[1]]: false,
+ })
+ const showNoResults = useMemo(() => {
+ return Object.values(hasNoResults).every((value) => value === true)
+ }, [hasNoResults])
+
+ const setNoResults = (index: string, value: boolean) => {
+ setHashNoResults((prev: IndexResults) => ({
+ ...prev,
+ [index]: value,
+ }))
+ }
+
+ return (
+
+ {status !== "loading" && showNoResults && }
+ {indices.map((indexName, index) => (
+
+
+
+
+ ))}
+
+ )
+}
+
+type SearchHitsProps = {
+ indexName: string
+ setNoResults: (index: string, value: boolean) => void
+}
+
+const SearchHits = ({ indexName, setNoResults }: SearchHitsProps) => {
+ const { hits } = useHits()
+ const { status } = useInstantSearch()
+ const { setIsOpen } = useSearch()
+
+ // group by lvl0
+ const grouped = useMemo(() => {
+ const grouped: GroupedHitType = {}
+ hits.forEach((hit) => {
+ if (hit.hierarchy.lvl0) {
+ if (!grouped[hit.hierarchy.lvl0]) {
+ grouped[hit.hierarchy.lvl0] = []
+ }
+ grouped[hit.hierarchy.lvl0].push(hit)
+ }
+ })
+
+ return grouped
+ }, [hits])
+
+ useEffect(() => {
+ if (status !== "loading" && status !== "stalled") {
+ setNoResults(indexName, hits.length === 0)
+ }
+ }, [hits, status])
+
+ const getLastAvailableHeirarchy = (item: HitType) => {
+ return (
+ Object.keys(item.hierarchy)
+ .reverse()
+ .find((key) => item.hierarchy[key as Hierarchy] !== null) || ""
+ )
+ }
+
+ const baseUrl = useMemo(() => getBaseUrl(), [])
+
+ const checkIfInternal = (url: string): boolean => {
+ const testRegex = new RegExp(`^${baseUrl}/api/(admin|store)`)
+ return testRegex.test(url)
+ }
+
+ return (
+
+ {Object.keys(grouped).map((groupName, index) => (
+
+
+ {grouped[groupName].map((item, index) => (
+ {
+ const target = e.target as Element
+ if (target.tagName.toLowerCase() === "div") {
+ target.querySelector("a")?.click()
+ }
+ }}
+ >
+
+
+
+ {item.type !== "lvl1" && (
+
+
+
+ )}
+ {
+ if (checkIfInternal(item.url)) {
+ e.preventDefault()
+ window.location.href = item.url
+ setIsOpen(false)
+ }
+ }}
+ />
+
+ ))}
+
+ ))}
+
+ )
+}
+
+export default SearchHitsWrapper
diff --git a/www/api-reference/components/Search/Modal/index.tsx b/www/api-reference/components/Search/Modal/index.tsx
new file mode 100644
index 0000000000..1b59140237
--- /dev/null
+++ b/www/api-reference/components/Search/Modal/index.tsx
@@ -0,0 +1,333 @@
+"use client"
+
+import React, { useEffect, useMemo, useRef, useState } from "react"
+import algoliasearch, { SearchClient } from "algoliasearch/lite"
+import { InstantSearch, SearchBox } from "react-instantsearch"
+import Modal from "../../Modal"
+import clsx from "clsx"
+import IconMagnifyingGlass from "../../Icons/MagnifyingGlass"
+import IconXMark from "../../Icons/XMark"
+import SearchEmptyQueryBoundary from "../EmptyQueryBoundary"
+import SearchSuggestions from "../Suggestions"
+import { useSearch } from "../../../providers/search"
+import checkArraySameElms from "../../../utils/array-same-elms"
+import SearchHitsWrapper from "../Hits"
+import Button from "../../Button"
+import Kbd from "../../MDXComponents/Kbd"
+import { OptionType } from "../../../hooks/use-select"
+import SelectBadge from "../../Select/Badge"
+import useKeyboardShortcut from "../../../hooks/use-keyboard-shortcut"
+import { findNextSibling, findPrevSibling } from "../../../utils/dom-utils"
+
+const algoliaClient = algoliasearch(
+ process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "temp",
+ process.env.NEXT_PUBLIC_ALGOLIA_API_KEY || "temp"
+)
+
+const searchClient: SearchClient = {
+ ...algoliaClient,
+ async search(requests) {
+ if (requests.every(({ params }) => !params?.query)) {
+ return Promise.resolve({
+ results: requests.map(() => ({
+ hits: [],
+ nbHits: 0,
+ nbPages: 0,
+ page: 0,
+ processingTimeMS: 0,
+ hitsPerPage: 0,
+ exhaustiveNbHits: false,
+ query: "",
+ params: "",
+ })),
+ })
+ }
+
+ return algoliaClient.search(requests)
+ },
+}
+
+const SearchModal = () => {
+ const modalRef = useRef(null)
+ const options: OptionType[] = useMemo(() => {
+ return [
+ {
+ value: "admin",
+ label: "Admin API",
+ },
+ {
+ value: "store",
+ label: "Store API",
+ },
+ {
+ value: "docs",
+ label: "Docs",
+ },
+ {
+ value: "user-guide",
+ label: "User Guide",
+ },
+ {
+ value: "plugins",
+ label: "Plugins",
+ },
+ {
+ value: "reference",
+ label: "References",
+ },
+ {
+ value: "ui",
+ label: "UI",
+ },
+ ]
+ }, [])
+ const { isOpen, setIsOpen, defaultFilters } = useSearch()
+ const [filters, setFilters] = useState(defaultFilters)
+ const formattedFilters: string = useMemo(() => {
+ let formatted = ""
+ filters.forEach((filter) => {
+ const split = filter.split("_")
+ split.forEach((f) => {
+ if (formatted.length) {
+ formatted += " OR "
+ }
+ formatted += `_tags:${f}`
+ })
+ })
+ return formatted
+ }, [filters])
+ const searchBoxRef = useRef(null)
+
+ const focusSearchInput = () =>
+ searchBoxRef.current?.querySelector("input")?.focus()
+
+ useEffect(() => {
+ if (!checkArraySameElms(defaultFilters, filters)) {
+ setFilters(defaultFilters)
+ }
+ }, [defaultFilters])
+
+ useEffect(() => {
+ if (isOpen && searchBoxRef.current) {
+ focusSearchInput()
+ }
+ }, [isOpen])
+
+ const handleKeyAction = (e: KeyboardEvent) => {
+ if (!isOpen) {
+ return
+ }
+ e.preventDefault()
+ const focusedItem = modalRef.current?.querySelector(":focus") as HTMLElement
+ if (!focusedItem) {
+ // focus the first data-hit
+ const nextItem = modalRef.current?.querySelector(
+ "[data-hit]"
+ ) as HTMLElement
+ nextItem?.focus()
+ return
+ }
+
+ const isHit = focusedItem.hasAttribute("data-hit")
+ const isInput = focusedItem.tagName.toLowerCase() === "input"
+
+ if (!isHit && !isInput) {
+ // ignore if focused items aren't input/data-hit
+ return
+ }
+
+ const lowerPressedKey = e.key.toLowerCase()
+
+ if (lowerPressedKey === "enter") {
+ if (isHit) {
+ // trigger click event of the focused element
+ focusedItem.click()
+ }
+ return
+ }
+
+ if (lowerPressedKey === "arrowup") {
+ // only hit items has action on arrow up
+ if (isHit) {
+ // find if there's a data-hit item before this one
+ const beforeItem = findPrevSibling(focusedItem, "[data-hit]")
+ if (!beforeItem) {
+ // focus the input
+ focusSearchInput()
+ } else {
+ // focus the previous item
+ beforeItem.focus()
+ }
+ }
+ } else if (lowerPressedKey === "arrowdown") {
+ // check if item is input or hit
+ if (isInput) {
+ // go to the first data-hit item
+ const nextItem = modalRef.current?.querySelector(
+ "[data-hit]"
+ ) as HTMLElement
+ nextItem?.focus()
+ } else {
+ // handle go down for hit items
+ // find if there's a data-hit item after this one
+ const afterItem = findNextSibling(focusedItem, "[data-hit]")
+ if (afterItem) {
+ // focus the next item
+ afterItem.focus()
+ }
+ }
+ }
+ }
+
+ useKeyboardShortcut({
+ metakey: false,
+ shortcutKeys: ["ArrowUp", "ArrowDown", "Enter"],
+ action: handleKeyAction,
+ checkEditing: false,
+ preventDefault: false,
+ })
+
+ return (
+ setIsOpen(false)}
+ ref={modalRef}
+ >
+
+
+ (
+
+ )}
+ resetIconComponent={() => (
+
+ )}
+ placeholder="Find something..."
+ autoFocus
+ formRef={searchBoxRef}
+ />
+
+
+
+ }>
+
+
+
+
+
+
+ setFilters(Array.isArray(value) ? [...value] : [value])
+ }
+ addSelected={(value) => setFilters((prev) => [...prev, value])}
+ removeSelected={(value) =>
+ setFilters((prev) => prev.filter((v) => v !== value))
+ }
+ showClearButton={false}
+ placeholder="Filters"
+ handleAddAll={(isAllSelected: boolean) => {
+ if (isAllSelected) {
+ setFilters(defaultFilters)
+ } else {
+ setFilters(options.map((option) => option.value))
+ }
+ }}
+ />
+
+
+
+ Navigation
+
+
+ ↑
+ ↓
+
+
+
+
+ Open Result
+
+ ↵
+
+
+
+
+ )
+}
+
+export default SearchModal
diff --git a/www/api-reference/components/Search/ModalOpener/index.tsx b/www/api-reference/components/Search/ModalOpener/index.tsx
new file mode 100644
index 0000000000..55d7cb34f9
--- /dev/null
+++ b/www/api-reference/components/Search/ModalOpener/index.tsx
@@ -0,0 +1,84 @@
+"use client"
+
+import clsx from "clsx"
+import IconMagnifyingGlass from "../../Icons/MagnifyingGlass"
+import InputText from "../../Input/Text"
+import { MouseEvent, useMemo } from "react"
+import Kbd from "../../MDXComponents/Kbd"
+import { useSearch } from "../../../providers/search"
+import { useMobile } from "../../../providers/mobile"
+import Button from "../../Button"
+import { usePageLoading } from "../../../providers/page-loading"
+import useKeyboardShortcut from "../../../hooks/use-keyboard-shortcut"
+
+const SearchModalOpener = () => {
+ const { setIsOpen } = useSearch()
+ const { isMobile } = useMobile()
+ const isApple = useMemo(() => {
+ return typeof navigator !== "undefined"
+ ? navigator.userAgent.toLowerCase().indexOf("mac") !== 0
+ : true
+ }, [])
+ const { isLoading } = usePageLoading()
+ useKeyboardShortcut({
+ shortcutKeys: ["k"],
+ action: () => setIsOpen((prev) => !prev),
+ })
+
+ const handleOpen = (
+ e:
+ | MouseEvent
+ | MouseEvent
+ | MouseEvent
+ ) => {
+ if (isLoading) {
+ return
+ }
+ e.preventDefault()
+ if ("blur" in e.target && typeof e.target.blur === "function") {
+ e.target.blur()
+ }
+ setIsOpen(true)
+ }
+
+ return (
+ <>
+ {isMobile && (
+
+ )}
+ {!isMobile && (
+
+
+ e.target.blur()}
+ tabIndex={-1}
+ />
+
+ {isApple ? "⌘" : "Ctrl"}
+ K
+
+
+ )}
+ >
+ )
+}
+
+export default SearchModalOpener
diff --git a/www/api-reference/components/Search/NoResults/index.tsx b/www/api-reference/components/Search/NoResults/index.tsx
new file mode 100644
index 0000000000..980e40cded
--- /dev/null
+++ b/www/api-reference/components/Search/NoResults/index.tsx
@@ -0,0 +1,14 @@
+import IconExclamationCircleSolid from "../../Icons/ExclamationCircleSolid"
+
+const SearchNoResult = () => {
+ return (
+
+
+
+ No results found. Try changing selected filters.
+
+
+ )
+}
+
+export default SearchNoResult
diff --git a/www/api-reference/components/Search/Suggestions/index.tsx b/www/api-reference/components/Search/Suggestions/index.tsx
new file mode 100644
index 0000000000..e2316795b7
--- /dev/null
+++ b/www/api-reference/components/Search/Suggestions/index.tsx
@@ -0,0 +1,49 @@
+import clsx from "clsx"
+import { useInstantSearch } from "react-instantsearch"
+import SearchHitGroupName from "../Hits/GroupName"
+
+const SearchSuggestions = () => {
+ const { setIndexUiState } = useInstantSearch()
+ const suggestions = [
+ "Authentication",
+ "Expanding fields",
+ "Selecting fields",
+ "Pagination",
+ "Query parameter types",
+ ]
+ return (
+
+
+ {suggestions.map((suggestion, index) => (
+
+ setIndexUiState({
+ query: suggestion,
+ })
+ }
+ key={index}
+ tabIndex={index}
+ data-hit
+ >
+
+ {suggestion}
+
+
+ ))}
+
+ )
+}
+
+export default SearchSuggestions
diff --git a/www/api-reference/components/SearchBar/index.tsx b/www/api-reference/components/SearchBar/index.tsx
deleted file mode 100644
index c9548ed1ab..0000000000
--- a/www/api-reference/components/SearchBar/index.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-"use client"
-
-import { DocSearch } from "@docsearch/react"
-
-import "@docsearch/css"
-
-const SearchBar = () => {
- return (
-
- )
-}
-
-export default SearchBar
diff --git a/www/api-reference/components/Select/Badge/index.tsx b/www/api-reference/components/Select/Badge/index.tsx
new file mode 100644
index 0000000000..720b8cd570
--- /dev/null
+++ b/www/api-reference/components/Select/Badge/index.tsx
@@ -0,0 +1,135 @@
+import { useCallback, useRef, useState } from "react"
+import useSelect from "../../../hooks/use-select"
+import clsx from "clsx"
+import SelectDropdown from "../Dropdown"
+import { SelectProps } from "../types"
+
+const SelectBadge = ({
+ value,
+ options,
+ setSelected,
+ addSelected,
+ removeSelected,
+ multiple,
+ className,
+ addAll = multiple,
+ handleAddAll,
+ ...props
+}: SelectProps) => {
+ const [open, setOpen] = useState(false)
+ const ref = useRef(null)
+ const dropdownRef = useRef(null)
+ const { isValueSelected, isAllSelected, handleChange, handleSelectAll } =
+ useSelect({
+ value,
+ options,
+ multiple,
+ setSelected,
+ removeSelected,
+ addSelected,
+ handleAddAll,
+ })
+
+ const getSelectedText = useCallback(() => {
+ let str = ""
+ const selectedOptions = options.filter((option) =>
+ value.includes(option.value)
+ )
+
+ if (isAllSelected) {
+ str = "All Areas"
+ } else {
+ if (
+ (!Array.isArray(value) && !value) ||
+ (Array.isArray(value) && !value.length)
+ ) {
+ str = "None selected"
+ } else {
+ str = selectedOptions[0].label
+ }
+ }
+
+ return (
+ <>
+
+ {str}
+
+ {!isAllSelected && selectedOptions.length > 1 && (
+
+ {" "}
+ + {selectedOptions.length}
+
+ )}
+ >
+ )
+ }, [isAllSelected, options, value])
+
+ return (
+
+
{
+ if (!dropdownRef.current?.contains(e.target as Element)) {
+ setOpen((prev) => !prev)
+ }
+ }}
+ >
+
+ Show results from:{" "}
+
+ {getSelectedText()}
+
+
+
+
+ )
+}
+
+export default SelectBadge
diff --git a/www/api-reference/components/Select/Dropdown/index.tsx b/www/api-reference/components/Select/Dropdown/index.tsx
new file mode 100644
index 0000000000..a21e842edd
--- /dev/null
+++ b/www/api-reference/components/Select/Dropdown/index.tsx
@@ -0,0 +1,151 @@
+import clsx from "clsx"
+import IconCheckMini from "../../Icons/CheckMini"
+import IconEllipseMiniSolid from "../../Icons/EllipseMiniSolid"
+import { OptionType } from "../../../hooks/use-select"
+import { forwardRef, useCallback, useEffect, useRef } from "react"
+
+type SelectDropdownProps = {
+ options: OptionType[]
+ open: boolean
+ setOpen: React.Dispatch>
+ addAll?: boolean
+ multiple?: boolean
+ isAllSelected: boolean
+ isValueSelected: (val: string) => boolean
+ handleSelectAll: () => void
+ handleChange?: (selectedValue: string, wasSelected: boolean) => void
+ parentRef?: React.RefObject
+ className?: string
+}
+
+const SelectDropdown = forwardRef(
+ function SelectDropdown(
+ {
+ open,
+ setOpen,
+ options,
+ addAll,
+ multiple = false,
+ isAllSelected,
+ isValueSelected,
+ handleSelectAll,
+ handleChange: handleSelectChange,
+ parentRef,
+ className,
+ },
+ passedRef
+ ) {
+ const ref = useRef(null)
+ const setRefs = useCallback(
+ (node: HTMLDivElement) => {
+ // 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]
+ )
+
+ const handleChange = (clickedValue: string, wasSelected: boolean) => {
+ handleSelectChange?.(clickedValue, wasSelected)
+ if (!multiple) {
+ setOpen(false)
+ }
+ }
+
+ const handleOutsideClick = useCallback(
+ (e: MouseEvent) => {
+ if (
+ open &&
+ !ref.current?.contains(e.target as Element) &&
+ !parentRef?.current?.contains(e.target as Element)
+ ) {
+ setOpen(false)
+ }
+ },
+ [open, parentRef, setOpen]
+ )
+
+ useEffect(() => {
+ document.body.addEventListener("click", handleOutsideClick)
+
+ return () => {
+ document.body.removeEventListener("click", handleOutsideClick)
+ }
+ }, [handleOutsideClick])
+
+ const getSelectOption = (option: OptionType, index: number) => {
+ const isSelected = option.isAllOption
+ ? isAllSelected
+ : isValueSelected(option.value)
+
+ return (
+ svg]:left-0.75 cursor-pointer [&>svg]:absolute [&>svg]:top-0.5",
+ !isSelected && "text-compact-small",
+ isSelected && "text-compact-small-plus"
+ )}
+ onClick={() => {
+ if (option.isAllOption) {
+ handleSelectAll()
+ } else {
+ handleChange(option.value, isSelected)
+ }
+ }}
+ >
+ {isSelected && (
+ <>
+ {multiple && (
+
+ )}
+ {!multiple && (
+
+ )}
+ >
+ )}
+ {option.label}
+
+ )
+ }
+
+ return (
+
+
+ {addAll &&
+ getSelectOption(
+ {
+ value: "all",
+ label: "All Areas",
+ isAllOption: true,
+ },
+ -1
+ )}
+ {options.map(getSelectOption)}
+
+
+ )
+ }
+)
+
+export default SelectDropdown
diff --git a/www/api-reference/components/Select/Input/index.tsx b/www/api-reference/components/Select/Input/index.tsx
new file mode 100644
index 0000000000..721adba8b9
--- /dev/null
+++ b/www/api-reference/components/Select/Input/index.tsx
@@ -0,0 +1,127 @@
+import clsx from "clsx"
+import IconChevronUpDown from "../../Icons/ChevronUpDown"
+import { useRef, useState } from "react"
+import Badge from "../../Badge"
+import IconXMarkMini from "../../Icons/XMarkMini"
+import useSelect from "../../../hooks/use-select"
+import SelectDropdown from "../Dropdown"
+import { SelectProps } from "../types"
+
+const SelectInput = ({
+ value,
+ options,
+ setSelected,
+ addSelected,
+ removeSelected,
+ multiple,
+ className,
+ addAll = multiple,
+ handleAddAll,
+ showClearButton = true,
+ ...props
+}: SelectProps) => {
+ const [open, setOpen] = useState(false)
+ const ref = useRef(null)
+ const dropdownRef = useRef(null)
+ const {
+ isValueSelected,
+ hasSelectedValue,
+ hasSelectedValues,
+ selectedValues,
+ isAllSelected,
+ handleChange,
+ handleSelectAll,
+ } = useSelect({
+ value,
+ options,
+ multiple,
+ setSelected,
+ removeSelected,
+ addSelected,
+ handleAddAll,
+ })
+
+ return (
+ {
+ if (!dropdownRef.current?.contains(e.target as Element)) {
+ setOpen((prev) => !prev)
+ }
+ }}
+ >
+ {hasSelectedValues && (
+
+
+ {(value as string[]).length}
+
+ {showClearButton && (
+ {
+ e.stopPropagation()
+ setSelected?.([])
+ }}
+ />
+ )}
+
+ )}
+
+ {!multiple && hasSelectedValue && selectedValues.length
+ ? selectedValues[0].label
+ : props.placeholder}
+
+
+
+
+
+ )
+}
+
+export default SelectInput
diff --git a/www/api-reference/components/Select/types.ts b/www/api-reference/components/Select/types.ts
new file mode 100644
index 0000000000..85369f2bd0
--- /dev/null
+++ b/www/api-reference/components/Select/types.ts
@@ -0,0 +1,9 @@
+import { OptionType, SelectOptions } from "../../hooks/use-select"
+
+export type SelectProps = {
+ options: OptionType[]
+ multiple?: boolean
+ addAll?: boolean
+ showClearButton?: boolean
+} & SelectOptions &
+ React.ComponentProps<"input">
diff --git a/www/api-reference/components/TextArea/index.tsx b/www/api-reference/components/TextArea/index.tsx
index d5fcaa471e..069ae76cb0 100644
--- a/www/api-reference/components/TextArea/index.tsx
+++ b/www/api-reference/components/TextArea/index.tsx
@@ -14,7 +14,7 @@ const TextArea = (props: TextAreaProps) => {
{...props}
className={clsx(
"bg-medusa-bg-field dark:bg-medusa-bg-field-dark shadow-button-secondary dark:shadow-button-secondary-dark",
- "border-medusa-border-loud-muted dark:border-medusa-border-loud-muted-dark rounded-sm border border-solid",
+ "border-medusa-border-base dark:border-medusa-border-base-dark rounded-sm border border-solid",
"pt-0.4 px-0.75 text-medium font-base pb-[9px]",
"hover:bg-medusa-bg-field-hover dark:hover:bg-medusa-bg-field-hover-dark",
"focus:border-medusa-border-interactive dark:focus:border-medusa-border-interactive-dark",
diff --git a/www/api-reference/css/code-theme.css b/www/api-reference/css/code-theme.css
deleted file mode 100644
index d484e515b5..0000000000
--- a/www/api-reference/css/code-theme.css
+++ /dev/null
@@ -1,313 +0,0 @@
-/** VS Code Dark Theme: https://github.com/PrismJS/prism-themes/blob/master/themes/prism-vsc-dark-plus.css **/
-
-/* .section-content pre {
- @apply rounded border border-transparent dark:border-medusa-code-border;
-} */
-
-/* .code-block {
- @apply relative;
- @apply xs:after:content-[''] xs:after:rounded xs:after:absolute xs:after:right-0 xs:after:top-0 xs:after:w-[calc(10%+24px)] xs:after:h-full xs:after:bg-code-fade;
-} */
-
-/* .prism-code {
- @apply relative xs:max-w-[90%];
-}
-
-.prism-code *::selection, .code-header::selection {
- @apply bg-medusa-code-text-highlight;
-}
-
-.prism-code:not(:hover)::-webkit-scrollbar-thumb,
-.prism-code:not(:hover)::-webkit-scrollbar-track {
- @apply xs:invisible;
-}
-
-.prism-code:hover::-webkit-scrollbar-thumb,
-.prism-code:hover::-webkit-scrollbar-track {
- @apply xs:opacity-100
-} */
-
-/* .prism-code {
- @apply bg-transparent break-words !outline-none;
-}
-
-.prism-code div {
- @apply !outline-none focus:!outline-none active:!outline-none;
-} */
-
-/* pre[class*="language-"],
-code[class*="language-"] {
- color: #d4d4d4;
- font-size: 13px;
- text-shadow: none;
- font-family: Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace;
- direction: ltr;
- text-align: left;
- white-space: pre;
- word-spacing: normal;
- word-break: normal;
- line-height: 1.5;
- -moz-tab-size: 4;
- -o-tab-size: 4;
- tab-size: 4;
- -webkit-hyphens: none;
- -moz-hyphens: none;
- -ms-hyphens: none;
- hyphens: none;
- position: relative;
-}
-
-pre[class*="language-"]::selection,
-code[class*="language-"]::selection,
-pre[class*="language-"] *::selection,
-code[class*="language-"] *::selection {
- text-shadow: none;
- background: #264F78;
-}
-
-@media print {
- pre[class*="language-"],
- code[class*="language-"] {
- text-shadow: none;
- }
-}
-
-pre[class*="language-"] {
- padding: 1em;
- margin: .5em 0;
- overflow: auto;
- background: #1e1e1e;
-}
-
-:not(pre) > code[class*="language-"] {
- padding: .1em .3em;
- border-radius: .3em;
- color: #db4c69;
- background: #1e1e1e;
-} */
-/*********************************************************
-* Tokens
-*/
-/* .namespace {
- opacity: .7;
-}
-
-.token.doctype .token.doctype-tag {
- color: #569CD6;
-}
-
-.token.doctype .token.name {
- color: #9cdcfe;
-}
-
-.token.comment,
-.token.prolog {
- color: #6a9955;
-}
-
-.token.punctuation,
-.language-html .language-css .token.punctuation,
-.language-html .language-javascript .token.punctuation {
- color: #d4d4d4;
-}
-
-.token.property,
-.token.tag,
-.token.boolean,
-.token.number,
-.token.constant,
-.token.symbol,
-.token.inserted,
-.token.unit {
- color: #b5cea8;
-}
-
-.token.selector,
-.token.attr-name,
-.token.string,
-.token.char,
-.token.builtin,
-.token.deleted {
- color: #ce9178;
-}
-
-.language-css .token.string.url {
- text-decoration: underline;
-}
-
-.token.operator,
-.token.entity {
- color: #d4d4d4;
-}
-
-.token.operator.arrow {
- color: #569CD6;
-}
-
-.token.atrule {
- color: #ce9178;
-}
-
-.token.atrule .token.rule {
- color: #c586c0;
-}
-
-.token.atrule .token.url {
- color: #9cdcfe;
-}
-
-.token.atrule .token.url .token.function {
- color: #dcdcaa;
-}
-
-.token.atrule .token.url .token.punctuation {
- color: #d4d4d4;
-}
-
-.token.keyword {
- color: #569CD6;
-}
-
-.token.keyword.module,
-.token.keyword.control-flow {
- color: #c586c0;
-}
-
-.token.function,
-.token.function .token.maybe-class-name {
- color: #dcdcaa;
-}
-
-.token.regex {
- color: #d16969;
-}
-
-.token.important {
- color: #569cd6;
-}
-
-.token.italic {
- font-style: italic;
-}
-
-.token.constant {
- color: #9cdcfe;
-}
-
-.token.class-name,
-.token.maybe-class-name {
- color: #4ec9b0;
-}
-
-.token.console {
- color: #9cdcfe;
-}
-
-.token.parameter {
- color: #9cdcfe;
-}
-
-.token.interpolation {
- color: #9cdcfe;
-}
-
-.token.punctuation.interpolation-punctuation {
- color: #569cd6;
-}
-
-.token.boolean {
- color: #569cd6;
-}
-
-.token.property,
-.token.variable,
-.token.imports .token.maybe-class-name,
-.token.exports .token.maybe-class-name {
- color: #9cdcfe;
-}
-
-.token.selector {
- color: #d7ba7d;
-}
-
-.token.escape {
- color: #d7ba7d;
-}
-
-.token.tag {
- color: #569cd6;
-}
-
-.token.tag .token.punctuation {
- color: #808080;
-}
-
-.token.cdata {
- color: #808080;
-}
-
-.token.attr-name {
- color: #9cdcfe;
-}
-
-.token.attr-value,
-.token.attr-value .token.punctuation {
- color: #ce9178;
-}
-
-.token.attr-value .token.punctuation.attr-equals {
- color: #d4d4d4;
-}
-
-.token.entity {
- color: #569cd6;
-}
-
-.token.namespace {
- color: #4ec9b0;
-} */
-/*********************************************************
-* Language Specific
-*/
-
-/* pre[class*="language-javascript"],
-code[class*="language-javascript"],
-pre[class*="language-jsx"],
-code[class*="language-jsx"],
-pre[class*="language-typescript"],
-code[class*="language-typescript"],
-pre[class*="language-tsx"],
-code[class*="language-tsx"] {
- color: #9cdcfe;
-}
-
-pre[class*="language-css"],
-code[class*="language-css"] {
- color: #ce9178;
-}
-
-pre[class*="language-html"],
-code[class*="language-html"] {
- color: #d4d4d4;
-}
-
-.language-regex .token.anchor {
- color: #dcdcaa;
-}
-
-.language-html .token.punctuation {
- color: #808080;
-} */
-/*********************************************************
-* Line highlighting
-*/
-/* pre[class*="language-"] > code[class*="language-"] {
- position: relative;
- z-index: 1;
-}
-
-.line-highlight.line-highlight {
- background: #f7ebc6;
- box-shadow: inset 5px 0 0 #f7d87c;
- z-index: 0;
-} */
\ No newline at end of file
diff --git a/www/api-reference/css/docsearch.css b/www/api-reference/css/docsearch.css
deleted file mode 100644
index 09c94bd596..0000000000
--- a/www/api-reference/css/docsearch.css
+++ /dev/null
@@ -1,232 +0,0 @@
-.DocSearch-Modal {
- @apply border border-solid !border-medusa-border-base dark:!border-medusa-border-base-dark;
- @apply !rounded !relative;
- @apply md:!m-[unset] md:w-[560px];
-}
-
-.DocSearch-SearchBar {
- @apply !p-0;
-}
-
-.DocSearch-Form {
- --docsearch-spacing: theme(margin[1.5]);
- --docsearch-searchbox-height: 56px;
- --docsearch-searchbox-focus-background: var(--docsearch-modal-background) !important;
-
- @apply !rounded-t !rounded-b-none border-0 border-b border-solid !border-medusa-border-base dark:!border-medusa-border-base-dark;
-}
-
-.DocSearch-LoadingIndicator svg, .DocSearch-MagnifierLabel svg {
- @apply !w-[20px] !h-[20px];
-}
-
-.DocSearch-Input {
- @apply !text-compact-large lg:!text-medium !pl-1;
- @apply placeholder:text-medusa-fg-muted dark:placeholder:text-medusa-fg-muted-dark;
-}
-
-.DocSearch-Dropdown {
- @apply !pt-0 !pb-2.5 !px-0;
- @apply !max-h-[416px];
-}
-
-.DocSearch-Hit-source {
- @apply !m-0 !text-compact-small-plus uppercase text-medusa-fg-muted dark:text-medusa-fg-muted-dark;
- @apply border-0 border-b border-solid border-medusa-border-base dark:border-medusa-border-base-dark;
- @apply !py-[10px] !px-1.5;
-}
-
-.DocSearch-Footer {
- @apply !hidden;
-}
-
-.DocSearch-Hit {
- @apply !p-0;
-}
-
-.DocSearch-Hit:not(.DocSearch-Hit--Child) .DocSearch-Hit-icon {
- @apply !w-2.5 !h-2.5 p-0.125 border border-solid border-medusa-border-strong dark:border-medusa-border-strong-dark;
- @apply rounded flex justify-center items-center;
- @apply before:content-[''] before:w-2 before:h-2 before:bg-no-repeat before:bg-center before:bg-contain before:bg-search-hit dark:before:bg-search-hit-dark;
-}
-
-.DocSearch-Hit-icon svg {
- @apply hidden;
-}
-
-.DocSearch-Hit--Child .DocSearch-Hit-icon {
- @apply hidden;
-}
-
-.DocSearch-Hit a {
- @apply !py-0.75 !px-1.5 !shadow-none !rounded-none;
-}
-
-.DocSearch-Hit:not(:last-of-type) a {
- @apply border-0 border-b border-solid border-medusa-border-base dark:border-medusa-border-base-dark;
-}
-
-.DocSearch-Hit-content-wrapper {
- @apply !mt-0 !mx-1;
-}
-
-.DocSearch-Hit-title,
-.DocSearch-Hit-title mark {
- @apply !text-medusa-fg-base dark:!text-medusa-fg-base-dark;
- @apply !text-compact-small-plus;
-}
-
-.DocSearch-Hit-path {
- @apply !text-medusa-fg-subtle dark:!text-medusa-fg-subtle-dark !text-compact-small;
-}
-
-.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path {
- --docsearch-hit-active-color: theme(colors.medusa.fg.subtle.DEFAULT);
-}
-
-html[data-theme="dark"] .DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path {
- --docsearch-hit-active-color: theme(colors.medusa.fg.subtle.dark);
-}
-
-.DocSearch-Hit[aria-selected=true] a {
- @apply !bg-medusa-bg-base-hover dark:!bg-medusa-bg-base-hover-dark;
-}
-
-.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-content-wrapper + .DocSearch-Hit-action:last-child {
- @apply h-1.5 w-1.5 border border-solid border-medusa-border-strong dark:border-medusa-border-strong-dark;
- @apply rounded bg-medusa-bg-base dark:bg-medusa-bg-base-dark p-0.125 flex justify-center items-center;
- @apply before:content-[''] before:w-[20px] before:h-[20px] before:bg-search-arrow dark:before:bg-search-arrow-dark before:bg-no-repeat before:bg-center;
-}
-
-.DocSearch-Hit-content-wrapper + .DocSearch-Hit-action:last-child svg,
-.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-content-wrapper + .DocSearch-Hit-action:last-child svg {
- @apply hidden;
-}
-
-.DocSearch-Hit[aria-selected=true] mark {
- @apply !no-underline;
-}
-
-.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree {
- @apply text-medusa-border-strong dark:text-medusa-border-strong-dark;
-}
-
-.DocSearch-Hit-Tree {
- @apply text-medusa-border-base dark:text-medusa-border-base-dark;
-}
-
-.DocSearch-HitsFooter {
- @apply z-[100] absolute bottom-0 left-0 w-full h-2.5 !bg-medusa-bg-base dark:!bg-medusa-bg-base-dark;
- @apply border-0 border-t border-solid border-medusa-border-base dark:border-medusa-border-base-dark;
-}
-
-.DocSearch-HitsFooter a {
- @apply !border-b-0;
-}
-
-.DocSearch-Reset {
- @apply !rounded transition-all duration-200 ease-ease;
- @apply hover:bg-medusa-bg-base-hover dark:hover:bg-medusa-bg-base-hover-dark;
-}
-
-.DocSearch-NoResults .DocSearch-Screen-Icon {
- @apply w-[20px] h-[20px] !p-0 flex justify-center items-center mt-0 mb-1 mx-auto;
- @apply before:content-[''] before:w-full before:h-full before:bg-no-repeat before:bg-center before:bg-contain;
- @apply before:bg-search-no-result dark:before:bg-search-no-result-dark;
-}
-
-.DocSearch-NoResults .DocSearch-Screen-Icon svg {
- @apply hidden;
-}
-
-.DocSearch-NoResults .DocSearch-Title {
- @apply !text-compact-small !pl-1;
-}
-
-.DocSearch-NoResults-Prefill-List {
- @apply text-center !text-compact-small-plus !pl-1;
-}
-
-.DocSearch-NoResults-Prefill-List li::marker {
- @apply content-[''];
-}
-
-.DocSearch-NoResults-Prefill-List li button {
- @apply text-medusa-fg-base dark:text-medusa-fg-base-dark;
-}
-.DocSearch-Button {
- @apply w-full !h-full !rounded lg:!border lg:!border-solid lg:!border-medusa-border-loud-muted lg:dark:!border-medusa-border-base-dark border-0;
- @apply lg:!bg-medusa-bg-field lg:dark:!bg-medusa-bg-field-dark !bg-transparent;
- @apply lg:hover:!bg-medusa-bg-field-hover lg:dark:hover:!bg-medusa-bg-field-hover-dark;
- @apply lg:disabled:!bg-medusa-bg-disabled lg:dark:disabled:!bg-medusa-bg-disabled-dark;
- @apply p-0 lg:!py-[5px] lg:!px-0.5 relative ml-0;
- @apply hover:!border-medusa-border-loud-muted hover:dark:!border-medusa-border-loud-muted-dark;
- @apply active:!border-medusa-border-interactive active:dark:!border-medusa-border-interactive-dark;
- @apply focus:!border-medusa-border-interactive focus:dark:!border-medusa-border-interactive-dark;
- @apply disabled:!border-medusa-border-base disabled:dark:!border-medusa-border-base-dark;
- @apply lg:!shadow-button-secondary lg:dark:!shadow-button-secondary-dark;
-}
-
-.DocSearch-Container {
- @apply !z-[1001] md:flex md:justify-center md:items-center;
-}
-
-.DocSearch-Button .DocSearch-Search-Icon {
- @apply invisible;
-}
-
-.DocSearch-Button-Container {
- @apply before:content-[''] before:h-[20px] before:w-[20px] before:absolute before:left-0.5 before:top-[5px];
- @apply before:bg-magnifying-glass dark:before:bg-magnifying-glass-dark before:bg-no-repeat;
-}
-
-.DocSearch-Button-Placeholder {
- @apply text-medusa-fg-muted dark:text-medusa-fg-muted-dark;
- @apply !pl-0.5 !text-compact-small lg:!block !hidden;
-}
-
-.DocSearch-Button-Keys {
- @apply w-fit !min-w-[unset] lg:!flex !hidden;
-}
-
-.DocSearch-Button-Key {
- @apply !shadow-none !rounded-md !text-compact-x-small-plus !font-base align-middle !p-0.25;
- @apply !border !border-solid !border-medusa-tag-neutral-border dark:!border-medusa-tag-neutral-border-dark;
- @apply [&span]:hidden [&:not(:last-child)]:!mr-0.25 last:!mr-0;
-}
-
-[class*=searchBox] {
- @apply lg:w-[280px] lg:max-w-[280px] lg:!h-2 lg:!p-0;
-}
-
-
-:root {
- --docsearch-searchbox-background: theme(colors.medusa.bg.field.DEFAULT) !important;
- --docsearch-searchbox-focus-background: theme(colors.medusa.bg.field.hover.DEFAULT) !important;
- --docsearch-searchbox-shadow: none !important;
- --docsearch-modal-height: 472px !important;
- --docsearch-modal-background: theme(colors.medusa.bg.base.DEFAULT) !important;
- --docsearch-modal-shadow: theme(boxShadow.modal) !important;
- --docsearch-container-background: theme(colors.medusa.bg.overlay.DEFAULT) !important;
- --docsearch-key-gradient: theme(colors.medusa.tag.neutral.bg.DEFAULT) !important;
- --docsearch-muted-color: theme(colors.medusa.tag.neutral.text.DEFAULT) !important;
- --docsearch-spacing: 12px theme(spacing[1.5]) !important;
- --docsearch-highlight-color: theme(colors.medusa.fg.muted.DEFAULT) !important;
- --docsearch-text-color: theme(colors.medusa.fg.base.DEFAULT) !important;
- --docsearch-hit-background: var(--docsearch-modal-background) !important;
- --docsearch-hit-height: auto !important;
- --docsearch-hit-active-color: var(--docsearch-text-color) !important;
- --docsearch-footer-height: 40px !important;
-}
-
-html[data-theme="dark"] {
- --docsearch-searchbox-background: theme(colors.medusa.bg.field.dark) !important;
- --docsearch-searchbox-focus-background: theme(colors.medusa.bg.field.hover.dark) !important;
- --docsearch-modal-background: theme(colors.medusa.bg.base.dark) !important;
- --docsearch-modal-shadow: theme(boxShadow.modal-dark) !important;
- --docsearch-container-background: theme(colors.medusa.bg.overlay.dark) !important;
- --docsearch-key-gradient: theme(colors.medusa.tag.neutral.bg.dark) !important;
- --docsearch-muted-color: theme(colors.medusa.tag.neutral.text.dark) !important;
- --docsearch-highlight-color: theme(colors.medusa.fg.muted.dark) !important;
- --docsearch-text-color: theme(colors.medusa.fg.base.dark) !important;
-}
\ No newline at end of file
diff --git a/www/api-reference/css/globals.css b/www/api-reference/css/globals.css
index 49d74e8737..202121129b 100644
--- a/www/api-reference/css/globals.css
+++ b/www/api-reference/css/globals.css
@@ -47,8 +47,13 @@
@apply !bg-medusa-code-text-highlight;
}
- body[data-modal="opened"] {
- overflow: hidden;
+ body[data-modal="opened"] {
+ @apply !overflow-hidden;
+ }
+
+ mark {
+ @apply bg-medusa-bg-highlight dark:bg-medusa-bg-highlight-dark;
+ @apply text-medusa-fg-interactive dark:text-medusa-fg-interactive-dark;
}
}
@@ -243,9 +248,9 @@
@apply inline-flex flex-row justify-center items-center;
@apply py-[5px] px-0.75 rounded-sm cursor-pointer;
@apply bg-button-neutral bg-medusa-button-neutral dark:bg-button-neutral-dark dark:bg-medusa-button-neutral-dark;
- @apply hover:bg-medusa-button-neutral-hover hover:bg-button-neutral-hover dark:hover:bg-medusa-button-neutral-hover-dark dark:hover:bg-button-neutral-hover-dark hover:no-underline;
- @apply active:bg-medusa-button-neutral-pressed active:bg-button-neutral-pressed dark:active:bg-medusa-button-neutral-pressed-dark dark:active:bg-button-neutral-pressed-dark;
- @apply focus:bg-medusa-button-neutral-pressed focus:bg-button-neutral-pressed dark:focus:bg-medusa-button-neutral-pressed-dark dark:focus:bg-button-neutral-pressed-dark;
+ @apply hover:bg-medusa-button-neutral-hover hover:bg-no-image dark:hover:bg-medusa-button-neutral-hover-dark hover:no-underline;
+ @apply active:bg-medusa-button-neutral-pressed active:bg-no-image dark:active:bg-medusa-button-neutral-pressed-dark;
+ @apply focus:bg-medusa-button-neutral-pressed focus:bg-no-image dark:focus:bg-medusa-button-neutral-pressed-dark;
@apply disabled:!bg-no-image disabled:bg-medusa-bg-disabled dark:disabled:bg-medusa-bg-disabled-dark;
@apply disabled:cursor-not-allowed;
@apply border border-solid border-medusa-border-base dark:border-medusa-border-base-dark;
@@ -263,12 +268,12 @@
@apply inline-flex flex-row justify-center items-center;
@apply py-[5px] px-0.75 rounded-sm cursor-pointer;
@apply bg-button-inverted bg-medusa-button-inverted dark:bg-button-inverted-dark dark:bg-medusa-button-inverted-dark;
- @apply hover:bg-medusa-button-inverted-hover hover:bg-button-inverted-hover dark:hover:bg-medusa-button-inverted-hover-dark dark:hover:bg-button-inverted-hover-dark hover:no-underline;
- @apply active:bg-medusa-button-inverted-pressed active:bg-button-inverted-pressed dark:active:bg-medusa-button-inverted-pressed-dark dark:active:bg-button-inverted-pressed-dark;
- @apply focus:bg-medusa-button-inverted-pressed focus:bg-button-inverted-pressed dark:focus:bg-medusa-button-inverted-pressed-dark dark:focus:bg-button-inverted-pressed-dark;
+ @apply hover:bg-medusa-button-inverted-hover hover:bg-no-image dark:hover:bg-medusa-button-inverted-hover-dark hover:no-underline;
+ @apply active:bg-medusa-button-inverted-pressed active:bg-no-image dark:active:bg-medusa-button-inverted-pressed-dark;
+ @apply focus:bg-medusa-button-inverted-pressed focus:bg-no-image dark:focus:bg-medusa-button-inverted-pressed-dark;
@apply shadow-button-colored active:shadow-button-colored-focused focus:shadow-button-colored-focused transition-shadow;
@apply dark:shadow-button-colored-dark dark:active:shadow-button-colored-focused-dark dark:focus:shadow-button-colored-focused-dark;
- @apply disabled:!bg-no-image disabled:bg-medusa-button-disabled dark:disabled:bg-medusa-button-disabled-dark;
+ @apply disabled:!bg-no-image disabled:bg-medusa-bg-disabled dark:disabled:bg-medusa-bg-disabled-dark;
@apply disabled:cursor-not-allowed disabled:border-medusa-border-base dark:disabled:border-medusa-border-base-dark;
@apply text-compact-small-plus text-medusa-fg-on-inverted dark:text-medusa-fg-on-inverted-dark;
@apply disabled:text-medusa-fg-disabled dark:disabled:text-medusa-fg-disabled-dark;
@@ -277,9 +282,8 @@
}
.btn-clear {
- @apply bg-transparent shadow-none border-0 outline-none;
+ @apply bg-transparent shadow-none border-0 outline-none cursor-pointer;
}
}
-@import url('./tooltip.css');
-@import url('./docsearch.css');
\ No newline at end of file
+@import url('./tooltip.css');
\ No newline at end of file
diff --git a/www/api-reference/css/tooltip.css b/www/api-reference/css/tooltip.css
index b3b3d50c26..6a6314bda8 100644
--- a/www/api-reference/css/tooltip.css
+++ b/www/api-reference/css/tooltip.css
@@ -1,13 +1,3 @@
-/* .react-tooltip {
- @apply !border !border-solid !border-medusa-border-base dark:!border-medusa-border-base-dark;
- @apply !rounded !text-compact-x-small-plus !shadow-tooltip dark:!shadow-tooltip-dark;
- @apply !py-0.4 !px-1 lg:block hidden;
-} */
-
-/* .react-tooltip-arrow {
- @apply hidden;
-} */
-
:root {
--rt-opacity: theme(opacity.100) !important;
--rt-color-dark: theme(colors.medusa.bg.base.DEFAULT) !important;
diff --git a/www/api-reference/hooks/use-keyboard-shortcut.tsx b/www/api-reference/hooks/use-keyboard-shortcut.tsx
new file mode 100644
index 0000000000..f90c949815
--- /dev/null
+++ b/www/api-reference/hooks/use-keyboard-shortcut.tsx
@@ -0,0 +1,70 @@
+import { useCallback, useEffect } from "react"
+import { usePageLoading } from "../providers/page-loading"
+
+type useKeyboardShortcutOptions = {
+ metakey?: boolean
+ shortcutKeys: string[]
+ action: (e: KeyboardEvent) => void
+ checkEditing?: boolean
+ preventDefault?: boolean
+}
+
+const useKeyboardShortcut = ({
+ metakey = true,
+ shortcutKeys,
+ action,
+ checkEditing = true,
+ preventDefault = true,
+}: useKeyboardShortcutOptions) => {
+ const { isLoading } = usePageLoading()
+
+ function isEditingContent(event: KeyboardEvent) {
+ const element = event.target as HTMLElement
+ const tagName = element.tagName
+ return (
+ element.isContentEditable ||
+ tagName === "INPUT" ||
+ tagName === "SELECT" ||
+ tagName === "TEXTAREA"
+ )
+ }
+
+ const checkKeysPressed = useCallback(
+ (pressedKey: string) => {
+ const lowerPressedKey = pressedKey.toLowerCase()
+ return shortcutKeys.some(
+ (value) => lowerPressedKey === value.toLowerCase()
+ )
+ },
+ [shortcutKeys]
+ )
+
+ const sidebarShortcut = useCallback(
+ (e: KeyboardEvent) => {
+ if (isLoading) {
+ return
+ }
+ if (
+ (!metakey || e.metaKey || e.ctrlKey) &&
+ checkKeysPressed(e.key) &&
+ (!checkEditing || !isEditingContent(e))
+ ) {
+ if (preventDefault) {
+ e.preventDefault()
+ }
+ action(e)
+ }
+ },
+ [isLoading, metakey, checkKeysPressed, checkEditing, action, preventDefault]
+ )
+
+ useEffect(() => {
+ window.addEventListener("keydown", sidebarShortcut)
+
+ return () => {
+ window.removeEventListener("keydown", sidebarShortcut)
+ }
+ }, [sidebarShortcut])
+}
+
+export default useKeyboardShortcut
diff --git a/www/api-reference/hooks/use-select.tsx b/www/api-reference/hooks/use-select.tsx
new file mode 100644
index 0000000000..d685d80db2
--- /dev/null
+++ b/www/api-reference/hooks/use-select.tsx
@@ -0,0 +1,93 @@
+import { useCallback, useMemo } from "react"
+
+export type OptionType = {
+ value: string
+ label: string
+ index?: string
+ isAllOption?: boolean
+}
+
+export type SelectOptions = {
+ value: string | string[]
+ multiple?: boolean
+ options: OptionType[]
+ setSelected?: (value: string | string[]) => void
+ addSelected?: (value: string) => void
+ removeSelected?: (value: string) => void
+ handleAddAll?: (isAllSelected: boolean) => void
+}
+
+const useSelect = ({
+ value,
+ options,
+ multiple = false,
+ setSelected,
+ addSelected,
+ removeSelected,
+ handleAddAll,
+}: SelectOptions) => {
+ const isValueSelected = useCallback(
+ (val: string) => {
+ return (
+ (typeof value === "string" && val === value) ||
+ (Array.isArray(value) && value.includes(val))
+ )
+ },
+ [value]
+ )
+
+ // checks if there are multiple selected values
+ const hasSelectedValues = useMemo(() => {
+ return multiple && Array.isArray(value) && value.length > 0
+ }, [value, multiple])
+
+ // checks if there are any selected values,
+ // whether multiple or one
+ const hasSelectedValue = useMemo(() => {
+ return hasSelectedValues || (typeof value === "string" && value.length)
+ }, [hasSelectedValues, value])
+
+ const selectedValues: OptionType[] = useMemo(() => {
+ if (typeof value === "string") {
+ const selectedValue = options.find((option) => option.value === value)
+ return selectedValue ? [selectedValue] : []
+ } else if (Array.isArray(value)) {
+ return options.filter((option) => value.includes(option.value))
+ }
+ return []
+ }, [options, value])
+
+ const isAllSelected = useMemo(() => {
+ return Array.isArray(value) && value.length === options.length
+ }, [options, value])
+
+ const handleChange = (selectedValue: string, wasSelected: boolean) => {
+ if (multiple) {
+ wasSelected
+ ? removeSelected?.(selectedValue)
+ : addSelected?.(selectedValue)
+ } else {
+ setSelected?.(selectedValue)
+ }
+ }
+
+ const handleSelectAll = () => {
+ if (handleAddAll) {
+ handleAddAll(isAllSelected)
+ } else {
+ setSelected?.(options.map((option) => option.value))
+ }
+ }
+
+ return {
+ isValueSelected,
+ hasSelectedValue,
+ hasSelectedValues,
+ selectedValues,
+ isAllSelected,
+ handleChange,
+ handleSelectAll,
+ }
+}
+
+export default useSelect
diff --git a/www/api-reference/package.json b/www/api-reference/package.json
index 3e2978962e..61d405a7be 100644
--- a/www/api-reference/package.json
+++ b/www/api-reference/package.json
@@ -42,6 +42,7 @@
"prism-react-renderer": "^2.0.6",
"react": "latest",
"react-dom": "latest",
+ "react-instantsearch": "^7.0.1",
"react-intersection-observer": "^9.5.2",
"react-tooltip": "^5.19.0",
"react-transition-group": "^4.4.5",
diff --git a/www/api-reference/providers/area.tsx b/www/api-reference/providers/area.tsx
index 214a36e45b..825879549e 100644
--- a/www/api-reference/providers/area.tsx
+++ b/www/api-reference/providers/area.tsx
@@ -1,7 +1,8 @@
"use client"
import type { Area } from "@/types/openapi"
-import { createContext, useContext, useState } from "react"
+import { createContext, useContext, useEffect, useState } from "react"
+import { useSearch } from "./search"
type AreaContextType = {
area: Area
@@ -17,6 +18,13 @@ type AreaProviderProps = {
const AreaProvider = ({ area: passedArea, children }: AreaProviderProps) => {
const [area, setArea] = useState(passedArea)
+ const { defaultFilters, setDefaultFilters } = useSearch()
+
+ useEffect(() => {
+ if (!defaultFilters.includes(area)) {
+ setDefaultFilters([area])
+ }
+ }, [area, defaultFilters, setDefaultFilters])
return (
(null)
+
+type MobileProviderProps = {
+ children: React.ReactNode
+}
+
+const MobileProvider = ({ children }: MobileProviderProps) => {
+ const [isMobile, setIsMobile] = useState(false)
+
+ const handleResize = useCallback(() => {
+ if (window.innerWidth < 1025 && !isMobile) {
+ setIsMobile(true)
+ } else if (window.innerWidth >= 1025 && isMobile) {
+ setIsMobile(false)
+ }
+ }, [isMobile])
+
+ useEffect(() => {
+ window.addEventListener("resize", handleResize)
+
+ return () => {
+ window.removeEventListener("resize", handleResize)
+ }
+ }, [handleResize])
+
+ useEffect(() => {
+ handleResize()
+ }, [])
+
+ return (
+
+ {children}
+
+ )
+}
+
+export default MobileProvider
+
+export const useMobile = () => {
+ const context = useContext(MobileContext)
+
+ if (!context) {
+ throw new Error("useMobile must be used within a MobileProvider")
+ }
+
+ return context
+}
diff --git a/www/api-reference/providers/modal.tsx b/www/api-reference/providers/modal.tsx
index c0d6c2a0a3..a52004696a 100644
--- a/www/api-reference/providers/modal.tsx
+++ b/www/api-reference/providers/modal.tsx
@@ -1,6 +1,6 @@
"use client"
-import React, { useContext, useEffect, useState } from "react"
+import React, { useContext, useState } from "react"
import { createContext } from "react"
import Modal, { ModalProps } from "../components/Modal"
@@ -23,14 +23,6 @@ const ModalProvider = ({ children }: ModalProviderProps) => {
setModalProps(null)
}
- useEffect(() => {
- if (modalProps) {
- document.body.setAttribute("data-modal", "opened")
- } else {
- document.body.removeAttribute("data-modal")
- }
- }, [modalProps])
-
return (
void
+}
+
+const PageLoadingContext = createContext(null)
+
+type PageLoadingProviderProps = {
+ children?: React.ReactNode
+}
+
+const PageLoadingProvider = ({ children }: PageLoadingProviderProps) => {
+ const [isLoading, setIsLoading] = useState(true)
+
+ return (
+
+ {children}
+
+ )
+}
+
+export default PageLoadingProvider
+
+export const usePageLoading = (): PageLoadingContextType => {
+ const context = useContext(PageLoadingContext)
+
+ if (!context) {
+ throw new Error("usePageLoading must be used inside a PageLoadingProvider")
+ }
+
+ return context
+}
diff --git a/www/api-reference/providers/search.tsx b/www/api-reference/providers/search.tsx
new file mode 100644
index 0000000000..5721630216
--- /dev/null
+++ b/www/api-reference/providers/search.tsx
@@ -0,0 +1,48 @@
+"use client"
+
+import { createContext, useContext, useState } from "react"
+import SearchModal from "../components/Search/Modal"
+
+type SearchContextType = {
+ isOpen: boolean
+ setIsOpen: React.Dispatch>
+ defaultFilters: string[]
+ setDefaultFilters: (value: string[]) => void
+}
+
+const SearchContext = createContext(null)
+
+type SearchProviderProps = {
+ children: React.ReactNode
+}
+
+const SearchProvider = ({ children }: SearchProviderProps) => {
+ const [isOpen, setIsOpen] = useState(false)
+ const [defaultFilters, setDefaultFilters] = useState([])
+
+ return (
+
+ {children}
+
+
+ )
+}
+
+export default SearchProvider
+
+export const useSearch = (): SearchContextType => {
+ const context = useContext(SearchContext)
+
+ if (!context) {
+ throw new Error("useSearch must be used inside a SearchProvider")
+ }
+
+ return context
+}
diff --git a/www/api-reference/providers/sidebar.tsx b/www/api-reference/providers/sidebar.tsx
index 3f8db934e4..d0129f7bf7 100644
--- a/www/api-reference/providers/sidebar.tsx
+++ b/www/api-reference/providers/sidebar.tsx
@@ -10,6 +10,7 @@ import {
useReducer,
useState,
} from "react"
+import { usePageLoading } from "./page-loading"
export enum SidebarItemSections {
TOP = "top",
@@ -167,6 +168,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
const [activePath, setActivePath] = useState("")
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false)
const [desktopSidebarOpen, setDesktopSidebarOpen] = useState(true)
+ const { isLoading, setIsLoading } = usePageLoading()
const findItemInSection = useCallback(
(
@@ -288,6 +290,12 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
}
}, [handleHashChange])
+ useEffect(() => {
+ if (isLoading && items.top.length && items.bottom.length) {
+ setIsLoading(false)
+ }
+ }, [items, isLoading, setIsLoading])
+
return (
{
+ addVariant("search-cancel", "&::-webkit-search-cancel-button")
+ }),
+ ],
}
diff --git a/www/api-reference/utils/array-same-elms.ts b/www/api-reference/utils/array-same-elms.ts
new file mode 100644
index 0000000000..a8f6810917
--- /dev/null
+++ b/www/api-reference/utils/array-same-elms.ts
@@ -0,0 +1,10 @@
+export default function checkArraySameElms(
+ arr1: Array,
+ arr2: Array
+): boolean {
+ if (arr1.length !== arr2.length) {
+ return false
+ }
+
+ return arr1.every((value, index) => value === arr2[index])
+}
diff --git a/www/api-reference/utils/dom-utils.ts b/www/api-reference/utils/dom-utils.ts
new file mode 100644
index 0000000000..cb2ef70b12
--- /dev/null
+++ b/www/api-reference/utils/dom-utils.ts
@@ -0,0 +1,29 @@
+export function findPrevSibling(
+ element: HTMLElement,
+ selector: string
+): HTMLElement | null {
+ let prevElement = element.previousElementSibling
+ while (prevElement !== null) {
+ if (prevElement.matches(selector)) {
+ return prevElement as HTMLElement
+ }
+ prevElement = prevElement.previousElementSibling
+ }
+
+ return null
+}
+
+export function findNextSibling(
+ element: HTMLElement,
+ selector: string
+): HTMLElement | null {
+ let nextElement = element.nextElementSibling
+ while (nextElement !== null) {
+ if (nextElement.matches(selector)) {
+ return nextElement as HTMLElement
+ }
+ nextElement = nextElement.nextElementSibling
+ }
+
+ return null
+}
diff --git a/www/api-reference/utils/get-base-url.ts b/www/api-reference/utils/get-base-url.ts
index 73348a78c8..0c54e1ac45 100644
--- a/www/api-reference/utils/get-base-url.ts
+++ b/www/api-reference/utils/get-base-url.ts
@@ -1,3 +1,3 @@
export default function getBaseUrl() {
- return process.env.NEXT_PUBLIC_BASE_URL || "http://locahost:3000"
+ return process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"
}
diff --git a/www/api-reference/yarn.lock b/www/api-reference/yarn.lock
index 9f58a27e24..9acdb7e2eb 100644
--- a/www/api-reference/yarn.lock
+++ b/www/api-reference/yarn.lock
@@ -135,6 +135,13 @@ __metadata:
languageName: node
linkType: hard
+"@algolia/events@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "@algolia/events@npm:4.0.1"
+ checksum: f398d815c6ed21ac08f6caadf1e9155add74ac05d99430191c3b1f1335fd91deaf468c6b304e6225c9885d3d44c06037c53def101e33d9c22daff175b2a65ca9
+ languageName: node
+ linkType: hard
+
"@algolia/logger-common@npm:4.19.1":
version: 4.19.1
resolution: "@algolia/logger-common@npm:4.19.1"
@@ -187,6 +194,23 @@ __metadata:
languageName: node
linkType: hard
+"@algolia/ui-components-highlight-vdom@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "@algolia/ui-components-highlight-vdom@npm:1.2.1"
+ dependencies:
+ "@algolia/ui-components-shared": 1.2.1
+ "@babel/runtime": ^7.0.0
+ checksum: cb768905ac19cde9b491e9d3ed9aa0cd9bd1c2db5a3fb723cbc6668e00917b3ca98864eb37dc5d9736fcfcd0951a695201f81b3994651d25eaa122a124549851
+ languageName: node
+ linkType: hard
+
+"@algolia/ui-components-shared@npm:1.2.1, @algolia/ui-components-shared@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "@algolia/ui-components-shared@npm:1.2.1"
+ checksum: 0ebbe1411a257efcd5b4535302ad85037c2b7de658fd05d0da681ed9eaebf66734a2327e08b20a9700a4cd6b2396463a5f91981aa35dc5b0adbb8d20aca96320
+ languageName: node
+ linkType: hard
+
"@alloc/quick-lru@npm:^5.2.0":
version: 5.2.0
resolution: "@alloc/quick-lru@npm:5.2.0"
@@ -236,7 +260,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7":
+"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7":
version: 7.22.10
resolution: "@babel/runtime@npm:7.22.10"
dependencies:
@@ -2047,6 +2071,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/dom-speech-recognition@npm:^0.0.1":
+ version: 0.0.1
+ resolution: "@types/dom-speech-recognition@npm:0.0.1"
+ checksum: 1df9283e40476f82b15cc7691c2f1177a185bf98af63d068f9333fbf4e334d2584b70babe2b9c69fcbe3c74293fcc0d47ce98c5717d8db361e70d88a8fbf9490
+ languageName: node
+ linkType: hard
+
"@types/estree-jsx@npm:^1.0.0":
version: 1.0.0
resolution: "@types/estree-jsx@npm:1.0.0"
@@ -2063,6 +2094,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/google.maps@npm:^3.45.3":
+ version: 3.53.6
+ resolution: "@types/google.maps@npm:3.53.6"
+ checksum: 08c43dc680edcc7f9f66262fe3598b2c7e250fa0240ec005daece1b16c125344e909c5cb865d22450d6e6cad2cd4f28cbb1e51f038627d78c21cc76768077f15
+ languageName: node
+ linkType: hard
+
"@types/hast@npm:*":
version: 3.0.0
resolution: "@types/hast@npm:3.0.0"
@@ -2081,6 +2119,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/hogan.js@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "@types/hogan.js@npm:3.0.1"
+ checksum: 8d2dc2809063852710a559746c8275af97bf5c84be1ad40fe240d8b5c91d266b0f841dc9774b5d1461ea42679b4dfeb4f1865a94995fc61a8e4081d3f11dc266
+ languageName: node
+ linkType: hard
+
"@types/js-yaml@npm:^4.0.0":
version: 4.0.5
resolution: "@types/js-yaml@npm:4.0.5"
@@ -2174,6 +2219,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/qs@npm:^6.5.3":
+ version: 6.9.7
+ resolution: "@types/qs@npm:6.9.7"
+ checksum: 157eb05f4c75790b0ebdcf7b0547ff117feabc8cda03c3cac3d3ea82bb19a1912e76a411df3eb0bdd01026a9770f07bc0e7e3fbe39ebb31c1be4564c16be35f1
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:18.2.7":
version: 18.2.7
resolution: "@types/react-dom@npm:18.2.7"
@@ -2319,7 +2371,7 @@ __metadata:
languageName: node
linkType: hard
-"abbrev@npm:^1.0.0":
+"abbrev@npm:1, abbrev@npm:^1.0.0":
version: 1.1.1
resolution: "abbrev@npm:1.1.1"
checksum: 3f762677702acb24f65e813070e306c61fafe25d4b2583f9dfc935131f774863f3addd5741572ed576bd69cabe473c5af18e1e108b829cb7b6b4747884f726e6
@@ -2408,6 +2460,17 @@ __metadata:
languageName: node
linkType: hard
+"algoliasearch-helper@npm:3.14.0":
+ version: 3.14.0
+ resolution: "algoliasearch-helper@npm:3.14.0"
+ dependencies:
+ "@algolia/events": ^4.0.1
+ peerDependencies:
+ algoliasearch: ">= 3.1 < 6"
+ checksum: 8c60aae2bcaa3f8eb547fd48cec0089a329dc5fec05e6c7364642fb2353256f11e4402ea3cec58c4a2bdad6a1720980fbd7dbab51be0b37b13a26b78705ddcc9
+ languageName: node
+ linkType: hard
+
"algoliasearch@npm:^4.0.0, algoliasearch@npm:^4.19.1":
version: 4.19.1
resolution: "algoliasearch@npm:4.19.1"
@@ -2523,6 +2586,7 @@ __metadata:
prism-react-renderer: ^2.0.6
react: latest
react-dom: latest
+ react-instantsearch: ^7.0.1
react-intersection-observer: ^9.5.2
react-tooltip: ^5.19.0
react-transition-group: ^4.4.5
@@ -4289,6 +4353,25 @@ __metadata:
languageName: node
linkType: hard
+"hogan.js@npm:^3.0.2":
+ version: 3.0.2
+ resolution: "hogan.js@npm:3.0.2"
+ dependencies:
+ mkdirp: 0.3.0
+ nopt: 1.0.10
+ bin:
+ hulk: ./bin/hulk
+ checksum: fa5c9d2eaf3fa712e72e67cce5e3435a1c5823282b81051514aefdca7d4b706cc4dbef7a34be19ee320c6ebaf3687d5781f12bc0aac04d3d902aa26861493679
+ languageName: node
+ linkType: hard
+
+"htm@npm:^3.0.0":
+ version: 3.1.1
+ resolution: "htm@npm:3.1.1"
+ checksum: 0de4c8fff2b8e76c162235ae80dbf93ca5eef1575bd50596a06ce9bebf1a6da5efc467417c53034a9ffa2ab9ecff819cbec041dc9087894b2b900ad4de26c7e7
+ languageName: node
+ linkType: hard
+
"html-encoding-sniffer@npm:^3.0.0":
version: 3.0.0
resolution: "html-encoding-sniffer@npm:3.0.0"
@@ -4399,6 +4482,29 @@ __metadata:
languageName: node
linkType: hard
+"instantsearch.js@npm:4.56.9":
+ version: 4.56.9
+ resolution: "instantsearch.js@npm:4.56.9"
+ dependencies:
+ "@algolia/events": ^4.0.1
+ "@algolia/ui-components-highlight-vdom": ^1.2.1
+ "@algolia/ui-components-shared": ^1.2.1
+ "@types/dom-speech-recognition": ^0.0.1
+ "@types/google.maps": ^3.45.3
+ "@types/hogan.js": ^3.0.0
+ "@types/qs": ^6.5.3
+ algoliasearch-helper: 3.14.0
+ hogan.js: ^3.0.2
+ htm: ^3.0.0
+ preact: ^10.10.0
+ qs: ^6.5.1 < 6.10
+ search-insights: ^2.6.0
+ peerDependencies:
+ algoliasearch: ">= 3.1 < 6"
+ checksum: acde452a6da992a01148cdcba89217292e624e2dce77682236b36f7d119586afbcc9f0c8f74cae49e81652ba1e79d72fed0a1aba29bbce0463e115fd1223e49d
+ languageName: node
+ linkType: hard
+
"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.5":
version: 1.0.5
resolution: "internal-slot@npm:1.0.5"
@@ -5613,6 +5719,13 @@ __metadata:
languageName: node
linkType: hard
+"mkdirp@npm:0.3.0":
+ version: 0.3.0
+ resolution: "mkdirp@npm:0.3.0"
+ checksum: cd9e54878490571df79770de1cdceba48ab6682c004616666d23a38315feaf5822d443aeb500ac298a12d7f6f5e11dc05cea3207d500e547d938218bf22d8629
+ languageName: node
+ linkType: hard
+
"mkdirp@npm:^1.0.3":
version: 1.0.4
resolution: "mkdirp@npm:1.0.4"
@@ -5806,6 +5919,17 @@ __metadata:
languageName: node
linkType: hard
+"nopt@npm:1.0.10":
+ version: 1.0.10
+ resolution: "nopt@npm:1.0.10"
+ dependencies:
+ abbrev: 1
+ bin:
+ nopt: ./bin/nopt.js
+ checksum: ddfbd892116a125fd68849ef564dd5b1f0a5ba0dbbf18782e9499e2efad8f4d3790635b47c6b5d3f7e014069e7b3ce5b8112687e9ae093fcd2678188c866fe28
+ languageName: node
+ linkType: hard
+
"nopt@npm:^6.0.0":
version: 6.0.0
resolution: "nopt@npm:6.0.0"
@@ -6229,6 +6353,13 @@ __metadata:
languageName: node
linkType: hard
+"preact@npm:^10.10.0":
+ version: 10.17.0
+ resolution: "preact@npm:10.17.0"
+ checksum: 43279a28cd1240c8692ef48751d32ec17548f2678a47cdb006e786ecbcb3b4db9ded97afb72f16248d56d91fbcf3974ae787cd9d186acc4f874fc58a32b894c0
+ languageName: node
+ linkType: hard
+
"prelude-ls@npm:^1.2.1":
version: 1.2.1
resolution: "prelude-ls@npm:1.2.1"
@@ -6290,6 +6421,13 @@ __metadata:
languageName: node
linkType: hard
+"qs@npm:^6.5.1 < 6.10":
+ version: 6.9.7
+ resolution: "qs@npm:6.9.7"
+ checksum: d0274b3c2daa9e7b350fb695fc4b5f7a1e65e266d5798a07936975f0848bdca6d7ad41cded19ad4af6a6253b97e43b497e988e728eab7a286f277b6dddfbade4
+ languageName: node
+ linkType: hard
+
"querystringify@npm:^2.1.1":
version: 2.2.0
resolution: "querystringify@npm:2.2.0"
@@ -6316,6 +6454,36 @@ __metadata:
languageName: node
linkType: hard
+"react-instantsearch-core@npm:7.0.1":
+ version: 7.0.1
+ resolution: "react-instantsearch-core@npm:7.0.1"
+ dependencies:
+ "@babel/runtime": ^7.1.2
+ algoliasearch-helper: 3.14.0
+ instantsearch.js: 4.56.9
+ use-sync-external-store: ^1.0.0
+ peerDependencies:
+ algoliasearch: ">= 3.1 < 5"
+ react: ">= 16.8.0 < 19"
+ checksum: 7796a0c8c9b7105aa31dc64762b37c72bccd8342d6cbdd6b55c3cb740f48af2fac5d8ba6b735b4739531720cf0ca48a478b7829728a237cd434abf4ab8fd2ff6
+ languageName: node
+ linkType: hard
+
+"react-instantsearch@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "react-instantsearch@npm:7.0.1"
+ dependencies:
+ "@babel/runtime": ^7.1.2
+ instantsearch.js: 4.56.9
+ react-instantsearch-core: 7.0.1
+ peerDependencies:
+ algoliasearch: ">= 3.1 < 5"
+ react: ">= 16.8.0 < 19"
+ react-dom: ">= 16.8.0 < 19"
+ checksum: 05cdafd17f6cf0523d29ebd9542b81a054fe0ef426a507b9d91653b35f5f567c3d0fb31b47feee600939f4feb561ae992cc4398e7d1aaa120029a01583088843
+ languageName: node
+ linkType: hard
+
"react-intersection-observer@npm:^9.5.2":
version: 9.5.2
resolution: "react-intersection-observer@npm:9.5.2"
@@ -6634,6 +6802,13 @@ __metadata:
languageName: node
linkType: hard
+"search-insights@npm:^2.6.0":
+ version: 2.7.0
+ resolution: "search-insights@npm:2.7.0"
+ checksum: b21701b88f9fcfc6e9c13c5b48aa61a5be2ac73d0a3fc5a9c50eea04b0465936d8badb5093fdba0310997b58b5d3d562a2e4bd681825c74199a4314846052064
+ languageName: node
+ linkType: hard
+
"semver@npm:^6.3.0, semver@npm:^6.3.1":
version: 6.3.1
resolution: "semver@npm:6.3.1"
@@ -7432,7 +7607,7 @@ __metadata:
languageName: node
linkType: hard
-"use-sync-external-store@npm:^1.2.0":
+"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.0":
version: 1.2.0
resolution: "use-sync-external-store@npm:1.2.0"
peerDependencies:
diff --git a/www/docs/.env.sample b/www/docs/.env.sample
index fd2fa8ec27..dc7c9c36e2 100644
--- a/www/docs/.env.sample
+++ b/www/docs/.env.sample
@@ -1 +1,3 @@
-API_URL=
\ No newline at end of file
+API_URL=
+NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME=
+NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME=
\ No newline at end of file
diff --git a/www/docs/docusaurus.config.js b/www/docs/docusaurus.config.js
index 61d5d3c776..7451217736 100644
--- a/www/docs/docusaurus.config.js
+++ b/www/docs/docusaurus.config.js
@@ -3,9 +3,6 @@ require("dotenv").config()
const fs = require("fs")
const reverseSidebar = require("./src/utils/reverseSidebar")
-const algoliaAppId = process.env.ALGOLIA_APP_ID || "temp"
-const algoliaApiKey = process.env.ALGOLIA_API_KEY || "temp"
-
const announcementBar = JSON.parse(fs.readFileSync("./announcement.json"))
/** @type {import('@medusajs/docs').MedusaDocusaurusConfig} */
@@ -46,16 +43,58 @@ const config = {
disableSwitch: false,
respectPrefersColorScheme: true,
},
- algolia: {
- apiKey: algoliaApiKey,
- indexName: "medusa-commerce",
- placeholder: "Search docs...",
- appId: algoliaAppId,
- contextualSearch: false,
- externalUrlRegex: "https://medusajs.com,https://docs.medusajs.com/api/",
- searchParameters: {
- tagFilters: "-reference",
+ algoliaConfig: {
+ appId: process.env.ALGOLIA_APP_ID || "temp",
+ apiKey: process.env.ALGOLIA_API_KEY || "temp",
+ indexNames: {
+ docs: process.env.NEXT_PUBLIC_DOCS_ALGOLIA_INDEX_NAME,
+ api: process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME,
},
+ filters: [
+ {
+ value: "docs",
+ label: "Docs",
+ },
+ {
+ value: "user-guide",
+ label: "User Guide",
+ },
+ {
+ value: "admin",
+ label: "Admin API",
+ },
+ {
+ value: "store",
+ label: "Store API",
+ },
+ {
+ value: "plugins",
+ label: "Plugins",
+ },
+ {
+ value: "reference",
+ label: "References",
+ },
+ {
+ value: "ui",
+ label: "UI",
+ },
+ ],
+ defaultFiltersByPath: [
+ {
+ path: "/user-guide",
+ filters: ["user-guide"],
+ },
+ {
+ path: "/references",
+ filters: ["reference"],
+ },
+ {
+ path: "/plugins",
+ filters: ["plugins"],
+ },
+ ],
+ defaultFilters: ["docs"],
},
prism: {
defaultLanguage: "js",
diff --git a/www/docs/package.json b/www/docs/package.json
index 2b14c96217..83f83010b7 100644
--- a/www/docs/package.json
+++ b/www/docs/package.json
@@ -37,6 +37,7 @@
"prism-react-renderer": "^1.3.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
+ "react-instantsearch": "^7.0.1",
"react-tooltip": "5.7.4",
"react-transition-group": "^4.4.5",
"react-uuid": "^2.0.0",
diff --git a/www/docs/src/components/Badge/index.tsx b/www/docs/src/components/Badge/index.tsx
index 417b74b20e..4f4ab310c6 100644
--- a/www/docs/src/components/Badge/index.tsx
+++ b/www/docs/src/components/Badge/index.tsx
@@ -3,14 +3,24 @@ import clsx from "clsx"
export type BadgeProps = {
className?: string
- variant: string
+ variant:
+ | "purple"
+ | "purple-dark"
+ | "orange"
+ | "orange-dark"
+ | "green"
+ | "green-dark"
+ | "blue"
+ | "blue-dark"
+ | "red"
+ | "neutral"
} & React.HTMLAttributes
const Badge: React.FC = ({ className, variant, children }) => {
return (
= ({ className, variant, children }) => {
"bg-medusa-tag-blue-bg dark:bg-medusa-tag-blue-bg-dark text-medusa-tag-blue-text dark:text-medusa-tag-blue-text-dark border-medusa-tag-blue-border dark:border-medusa-tag-blue-border-dark",
variant === "blue-dark" &&
"bg-medusa-tag-blue-bg-dark text-medusa-tag-blue-text-dark border-medusa-tag-blue-border-dark",
+ variant === "red" &&
+ "bg-medusa-tag-red-bg dark:bg-medusa-tag-red-bg-dark text-medusa-tag-red-text dark:text-medusa-tag-red-text-dark border-medusa-tag-red-border dark:border-medusa-tag-red-border-dark",
+ variant === "neutral" &&
+ "bg-medusa-tag-neutral-bg dark:bg-medusa-tag-neutral-bg-dark text-medusa-tag-neutral-text dark:text-medusa-tag-neutral-text-dark border-medusa-tag-neutral-border dark:border-medusa-tag-neutral-border-dark",
"badge",
className
)}
diff --git a/www/docs/src/components/Button/index.tsx b/www/docs/src/components/Button/index.tsx
index 02c0360c88..e3e8db8b52 100644
--- a/www/docs/src/components/Button/index.tsx
+++ b/www/docs/src/components/Button/index.tsx
@@ -2,6 +2,7 @@ import React from "react"
import clsx from "clsx"
export type ButtonProps = {
+ variant?: "secondary" | "primary" | "clear"
btnTypeClassName?: string
className?: string
onClick?: React.MouseEventHandler
@@ -9,6 +10,7 @@ export type ButtonProps = {
} & React.HTMLAttributes
const Button: React.FC = ({
+ variant,
className = "",
btnTypeClassName,
onClick,
@@ -18,7 +20,10 @@ const Button: React.FC = ({
return (