diff --git a/.changeset/spotty-dragons-shave.md b/.changeset/spotty-dragons-shave.md new file mode 100644 index 0000000000000..2d6da10efd8a7 --- /dev/null +++ b/.changeset/spotty-dragons-shave.md @@ -0,0 +1,10 @@ +--- +"@medusajs/medusa": minor +"@medusajs/product": minor +"@medusajs/core-flows": minor +"@medusajs/types": minor +"@medusajs/utils": minor +"@medusajs/dashboard": minor +--- + +feat(): allow linking a subset of an option's values to the product diff --git a/packages/admin/dashboard/package.json b/packages/admin/dashboard/package.json index 349eae20fa48c..bd0c41bf9ab90 100644 --- a/packages/admin/dashboard/package.json +++ b/packages/admin/dashboard/package.json @@ -3,7 +3,7 @@ "version": "2.11.3", "scripts": { "generate:static": "node ./scripts/generate-currencies.js && prettier --write ./src/lib/currencies.ts", - "dev": "vite", + "dev": "../../../node_modules/.bin/vite", "build": "yarn run -T tsup && node ./scripts/generate-types.js", "build:preview": "vite build", "preview": "vite preview", diff --git a/packages/admin/dashboard/src/components/inputs/combobox/combobox.tsx b/packages/admin/dashboard/src/components/inputs/combobox/combobox.tsx index a8875443289a0..0bda9b9e22f81 100644 --- a/packages/admin/dashboard/src/components/inputs/combobox/combobox.tsx +++ b/packages/admin/dashboard/src/components/inputs/combobox/combobox.tsx @@ -15,7 +15,7 @@ import { TrianglesMini, XMarkMini, } from "@medusajs/icons" -import { clx, Text } from "@medusajs/ui" +import { Badge, clx, Text } from "@medusajs/ui" import { matchSorter } from "match-sorter" import { ComponentPropsWithoutRef, @@ -59,6 +59,7 @@ interface ComboboxProps noResultsPlaceholder?: ReactNode allowClear?: boolean forceHideInput?: boolean // always hide input -> used for singe value select that don't have query/filter + displayMode?: "count" | "chips" // how to display multiple selected values } const ComboboxImpl = ( @@ -76,6 +77,7 @@ const ComboboxImpl = ( noResultsPlaceholder, allowClear, forceHideInput, + displayMode = "count", ...inputProps }: ComboboxProps, ref: ForwardedRef @@ -143,6 +145,15 @@ const ComboboxImpl = ( } } + const handleRemoveValue = (valueToRemove: string) => { + if (!isArrayValue || !Array.isArray(selectedValues)) { + return + } + + const newValues = selectedValues.filter((v) => v !== valueToRemove) as T + handleValueChange(newValues) + } + /** * Filter and sort the options based on the search value, * and whether the value is already selected. @@ -235,109 +246,179 @@ const ComboboxImpl = ( startTransition(() => handleSearchChange(query)) }} > -
- {showTag && ( - - )} -
- {showSelected && ( -
+ {Array.isArray(selectedValues) && + selectedValues.map((value) => { + const option = options.find((o) => o.value === value) + if (!option) return null + + return ( + + {option.label} + + + ) + })} +
+ setOpen(true)} className={clx( - "pointer-events-none absolute inset-y-0 flex size-full items-center", - { - "start-[calc(var(--tag-width)+8px)]": showTag, - "start-2": !showTag, - } + "txt-compact-small text-ui-fg-base !placeholder:text-ui-fg-muted transition-fg size-full cursor-pointer bg-transparent pe-8 ps-1 outline-none focus:cursor-text" )} + placeholder={ + Array.isArray(selectedValues) && selectedValues.length > 0 + ? undefined + : placeholder + } + {...inputProps} + /> +
+ { + return ( + + ) + }} + /> +
+ ) : ( +
+ {showTag && ( +
+ {selectedValues.length} + + )} - {hideInput && ( -
+ {showSelected && ( +
+ + {t("general.selected")} + +
+ )} + {hideInput && ( +
+ + {selectedLabel} + +
+ )} + setOpen(true)} className={clx( - "pointer-events-none absolute inset-y-0 flex size-full items-center overflow-hidden", + "txt-compact-small text-ui-fg-base !placeholder:text-ui-fg-muted transition-fg size-full cursor-pointer bg-transparent pe-8 ps-2 outline-none focus:cursor-text", { - "start-[calc(var(--tag-width)+8px)]": showTag, - "start-2": !showTag, + "opacity-0": hideInput, + "ps-2": !showTag, + "ps-[calc(var(--tag-width)+8px)]": showTag, } )} + placeholder={hidePlaceholder ? undefined : placeholder} + {...inputProps} + /> +
+ {allowClear && controlledValue && ( +
+ + )} - setOpen(true)} - className={clx( - "txt-compact-small text-ui-fg-base !placeholder:text-ui-fg-muted transition-fg size-full cursor-pointer bg-transparent pe-8 ps-2 outline-none focus:cursor-text", - "hover:bg-ui-bg-field-hover", - { - "opacity-0": hideInput, - "ps-2": !showTag, - "ps-[calc(var(--tag-width)+8px)]": showTag, - } - )} - placeholder={hidePlaceholder ? undefined : placeholder} - {...inputProps} + { + return ( + + ) + }} />
- {allowClear && controlledValue && ( - - )} - { - return ( - - ) - }} - /> - + )} {t("products.fields.title.label")} - + ) @@ -43,7 +46,10 @@ export const ProductCreateGeneralSection = ({ {t("products.fields.subtitle.label")} - + ) @@ -62,7 +68,10 @@ export const ProductCreateGeneralSection = ({ {t("fields.handle")} - + ) @@ -80,7 +89,10 @@ export const ProductCreateGeneralSection = ({ {t("products.fields.description.label")} -