feat(dashboard): Product create from - details (#7121)

**What**
- First part of the product creation form.
- New components:
  - ChipInput - Allows users to input chips into a input field. Chips are created by hitting the `,` or `Enter / Return` keys. Deleting a chip is done by hitting `Backspace` when the cursor is next to chip, or clicking the `X` button in the chip. Used for inputting option values.
  - SortableList - A sortable drag-n-drop list that allows the user to re-arrange the order of items. Used for re-arranging the ranking of variants.
  - ChipGroup - New re-usable component that is used to render a group of values as Chips. This should be used for SplitView form items.
  - CategoryCombobox - (WIP) Nested Combobox component for selecting multiple categories a product should be associated with.
- New hooks:
  - useComboboxData - Hook for easily managing the state of comboboxes.
  - useDebouncedSearch - Hook for managing debounced search queries.
This commit is contained in:
Kasper Fabricius Kristensen
2024-05-03 10:37:36 +00:00
committed by GitHub
parent e42308557e
commit fdee748eed
84 changed files with 2837 additions and 1588 deletions
@@ -0,0 +1,111 @@
import { XMarkMini } from "@medusajs/icons"
import { Button, clx } from "@medusajs/ui"
import { Children, PropsWithChildren, createContext, useContext } from "react"
import { useTranslation } from "react-i18next"
type ChipGroupVariant = "base" | "component"
type ChipGroupProps = PropsWithChildren<{
onClearAll?: () => void
onRemove?: (index: number) => void
variant?: ChipGroupVariant
className?: string
}>
type GroupContextValue = {
onRemove?: (index: number) => void
variant: ChipGroupVariant
}
const GroupContext = createContext<GroupContextValue | null>(null)
const useGroupContext = () => {
const context = useContext(GroupContext)
if (!context) {
throw new Error("useGroupContext must be used within a ChipGroup component")
}
return context
}
const Group = ({
onClearAll,
onRemove,
variant = "component",
className,
children,
}: ChipGroupProps) => {
const { t } = useTranslation()
const showClearAll = !!onClearAll && Children.count(children) > 0
return (
<GroupContext.Provider value={{ onRemove, variant }}>
<ul
role="application"
className={clx("flex flex-wrap items-center gap-2", className)}
>
{children}
{showClearAll && (
<li>
<Button
size="small"
variant="transparent"
type="button"
onClick={onClearAll}
className="text-ui-fg-muted active:text-ui-fg-subtle"
>
{t("actions.clearAll")}
</Button>
</li>
)}
</ul>
</GroupContext.Provider>
)
}
type ChipProps = PropsWithChildren<{
index: number
className?: string
}>
const Chip = ({ index, className, children }: ChipProps) => {
const { onRemove, variant } = useGroupContext()
return (
<li
className={clx(
"bg-ui-bg-component shadow-borders-base flex items-center divide-x overflow-hidden rounded-md",
{
"bg-ui-bg-component": variant === "component",
"bg-ui-bg-base-": variant === "base",
},
className
)}
>
<span className="txt-compact-small-plus flex items-center justify-center px-2 py-1">
{children}
</span>
{!!onRemove && (
<button
onClick={() => onRemove(index)}
type="button"
className={clx(
"text-ui-fg-muted active:text-ui-fg-subtle transition-fg flex items-center justify-center p-1",
{
"hover:bg-ui-bg-component-hover active:bg-ui-bg-component-pressed":
variant === "component",
"hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed":
variant === "base",
}
)}
>
<XMarkMini />
</button>
)}
</li>
)
}
export const ChipGroup = Object.assign(Group, { Chip })
@@ -0,0 +1 @@
export * from "./chip-group"