1863 - Support reference attribute reordering (#946)
* Support reference attribute reordering * Update attribute handlers tests
This commit is contained in:
parent
4b8c2ea5e7
commit
b07bb08ade
19 changed files with 615 additions and 297 deletions
|
@ -1,9 +1,8 @@
|
|||
import { createAttributeMultiChangeHandler } from "@saleor/attributes/utils/handlers";
|
||||
import { AttributeInputData } from "@saleor/components/Attributes";
|
||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
|
||||
import { createAttributeMultiChangeHandler } from "./handlers";
|
||||
|
||||
const attributes: FormsetData<AttributeInputData, string[]> = [
|
||||
{
|
||||
data: {
|
|
@ -1,14 +1,23 @@
|
|||
import { AttributeInput } from "@saleor/components/Attributes";
|
||||
import {
|
||||
AttributeInput,
|
||||
AttributeInputData
|
||||
} from "@saleor/components/Attributes";
|
||||
import {
|
||||
FileUpload,
|
||||
FileUploadVariables
|
||||
} from "@saleor/files/types/FileUpload";
|
||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||
import {
|
||||
FormsetAtomicData,
|
||||
FormsetChange,
|
||||
FormsetData
|
||||
} from "@saleor/hooks/useFormset";
|
||||
import { PageDetails_page_attributes } from "@saleor/pages/types/PageDetails";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import {
|
||||
AttributeInputTypeEnum,
|
||||
AttributeValueInput
|
||||
} from "@saleor/types/globalTypes";
|
||||
import { move, toggle } from "@saleor/utils/lists";
|
||||
import { MutationFetchResult } from "react-apollo";
|
||||
|
||||
import {
|
||||
|
@ -17,6 +26,99 @@ import {
|
|||
} from "../types/AttributeValueDelete";
|
||||
import { getFileValuesToUploadFromAttributes, isFileValueUnused } from "./data";
|
||||
|
||||
export function createAttributeChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<string> {
|
||||
return (attributeId: string, value: string) => {
|
||||
triggerChange();
|
||||
changeAttributeData(attributeId, value === "" ? [] : [value]);
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeMultiChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
attributes: FormsetData<AttributeInputData, string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<string> {
|
||||
return (attributeId: string, value: string) => {
|
||||
const attribute = attributes.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
|
||||
const newAttributeValues = toggle(
|
||||
value,
|
||||
attribute.value,
|
||||
(a, b) => a === b
|
||||
);
|
||||
|
||||
triggerChange();
|
||||
changeAttributeData(attributeId, newAttributeValues);
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeReferenceChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<string[]> {
|
||||
return (attributeId: string, values: string[]) => {
|
||||
changeAttributeData(attributeId, values);
|
||||
triggerChange();
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeFileChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
attributesWithNewFileValue: FormsetData<FormsetData<null, File>>,
|
||||
addAttributeNewFileValue: (data: FormsetAtomicData<null, File>) => void,
|
||||
changeAttributeNewFileValue: FormsetChange<File>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<File> {
|
||||
return (attributeId: string, value: File) => {
|
||||
triggerChange();
|
||||
|
||||
const newFileValueAssigned = attributesWithNewFileValue.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
|
||||
if (newFileValueAssigned) {
|
||||
changeAttributeNewFileValue(attributeId, value);
|
||||
} else {
|
||||
addAttributeNewFileValue({
|
||||
data: null,
|
||||
id: attributeId,
|
||||
label: null,
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
changeAttributeData(attributeId, value ? [value.name] : []);
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeValueReorderHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
attributes: FormsetData<AttributeInputData, string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<ReorderEvent> {
|
||||
return (attributeId: string, reorder: ReorderEvent) => {
|
||||
triggerChange();
|
||||
|
||||
const attribute = attributes.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
|
||||
const reorderedValues = move(
|
||||
attribute.value[reorder.oldIndex],
|
||||
attribute.value,
|
||||
(a, b) => a === b,
|
||||
reorder.newIndex
|
||||
);
|
||||
|
||||
changeAttributeData(attributeId, reorderedValues);
|
||||
};
|
||||
}
|
||||
|
||||
interface AttributesArgs {
|
||||
attributes: AttributeInput[];
|
||||
updatedFileAttributes: AttributeValueInput[];
|
||||
|
|
|
@ -17,7 +17,7 @@ import { PageErrorWithAttributesFragment } from "@saleor/fragments/types/PageErr
|
|||
import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment";
|
||||
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
|
||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { ReorderAction } from "@saleor/types";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
import { getProductErrorMessage } from "@saleor/utils/errors";
|
||||
import getPageErrorMessage from "@saleor/utils/errors/page";
|
||||
|
@ -56,12 +56,12 @@ export interface AttributesProps {
|
|||
ProductErrorWithAttributesFragment | PageErrorWithAttributesFragment
|
||||
>;
|
||||
title?: React.ReactNode;
|
||||
onChange: FormsetChange;
|
||||
onMultiChange: FormsetChange;
|
||||
onFileChange: FormsetChange;
|
||||
onReferencesRemove?: FormsetChange; // TODO: temporairy optional, should be changed to required, after all pages implement it
|
||||
onReferencesAddClick?: (attribute: AttributeInput) => void; // TODO: temporairy optional, should be changed to required, after all pages implement it
|
||||
onReferencesReorder?: ReorderAction; // TODO: temporairy optional, should be changed to required, after all pages implement it
|
||||
onChange: FormsetChange<string>;
|
||||
onMultiChange: FormsetChange<string>;
|
||||
onFileChange: FormsetChange<File>;
|
||||
onReferencesRemove: FormsetChange<string[]>;
|
||||
onReferencesAddClick: (attribute: AttributeInput) => void;
|
||||
onReferencesReorder: FormsetChange<ReorderEvent>;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
|
@ -328,8 +328,12 @@ const Attributes: React.FC<AttributesProps> = ({
|
|||
attribute.value?.filter(id => id !== value)
|
||||
)
|
||||
}
|
||||
onValueReorder={onReferencesReorder}
|
||||
onValueReorder={event =>
|
||||
onReferencesReorder(attribute.id, event)
|
||||
}
|
||||
loading={loading}
|
||||
error={!!error}
|
||||
helperText={getErrorMessage(error, intl)}
|
||||
/>
|
||||
</ExtendedAttributeRow>
|
||||
) : attribute.data.inputType ===
|
||||
|
|
|
@ -24,4 +24,11 @@ storiesOf("Generics / Sortable chips field", module)
|
|||
.addDecorator(CardDecorator)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <SortableChipsField {...props} />)
|
||||
.add("loading", () => <SortableChipsField {...props} loading={true} />);
|
||||
.add("loading", () => <SortableChipsField {...props} loading={true} />)
|
||||
.add("with error", () => (
|
||||
<SortableChipsField
|
||||
{...props}
|
||||
error={true}
|
||||
helperText="Something went wrong"
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import { ReorderAction } from "@saleor/types";
|
||||
import React from "react";
|
||||
import { SortableContainerProps } from "react-sortable-hoc";
|
||||
|
@ -13,6 +14,9 @@ const useStyles = makeStyles(
|
|||
background: "#fff",
|
||||
color: theme.palette.primary.dark,
|
||||
marginBottom: theme.spacing(1)
|
||||
},
|
||||
errorText: {
|
||||
color: theme.palette.error.light
|
||||
}
|
||||
}),
|
||||
{
|
||||
|
@ -28,12 +32,21 @@ export interface SortableChipsFieldValueType {
|
|||
export interface SortableChipsFieldProps extends SortableContainerProps {
|
||||
loading?: boolean;
|
||||
values: SortableChipsFieldValueType[];
|
||||
error?: boolean;
|
||||
helperText?: string;
|
||||
onValueDelete: (id: string) => void;
|
||||
onValueReorder: ReorderAction;
|
||||
}
|
||||
|
||||
const SortableChipsField: React.FC<SortableChipsFieldProps> = props => {
|
||||
const { loading, values, onValueDelete, onValueReorder } = props;
|
||||
const {
|
||||
loading,
|
||||
values,
|
||||
error,
|
||||
helperText,
|
||||
onValueDelete,
|
||||
onValueReorder
|
||||
} = props;
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
|
@ -57,6 +70,11 @@ const SortableChipsField: React.FC<SortableChipsFieldProps> = props => {
|
|||
/>
|
||||
))
|
||||
)}
|
||||
{error && (
|
||||
<Typography variant="caption" className={classes.errorText}>
|
||||
{helperText}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</SortableContainer>
|
||||
);
|
||||
|
|
|
@ -148,6 +148,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
|
|||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { OutputData } from "@editorjs/editorjs";
|
||||
import { getAttributesDisplayData } from "@saleor/attributes/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createAttributeValueReorderHandler
|
||||
} from "@saleor/attributes/utils/handlers";
|
||||
import { AttributeInput } from "@saleor/components/Attributes";
|
||||
import { MetadataFormData } from "@saleor/components/Metadata";
|
||||
import { RichTextEditorChange } from "@saleor/components/RichTextEditor";
|
||||
|
@ -16,13 +23,8 @@ import {
|
|||
} from "@saleor/pages/types/PageDetails";
|
||||
import { getAttributeInputFromPage } from "@saleor/pages/utils/data";
|
||||
import { createPageTypeSelectHandler } from "@saleor/pages/utils/handlers";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler
|
||||
} from "@saleor/products/utils/handlers";
|
||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import getPublicationData from "@saleor/utils/data/getPublicationData";
|
||||
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
|
||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||
|
@ -59,6 +61,7 @@ export interface PageUpdateHandlers {
|
|||
selectAttributeMulti: FormsetChange<string>;
|
||||
selectAttributeReference: FormsetChange<string[]>;
|
||||
selectAttributeFile: FormsetChange<File>;
|
||||
reorderAttributeValue: FormsetChange<ReorderEvent>;
|
||||
}
|
||||
export interface UsePageUpdateFormResult {
|
||||
change: FormChange;
|
||||
|
@ -150,6 +153,11 @@ function usePageForm(
|
|||
attributesWithNewFileValue.change,
|
||||
triggerChange
|
||||
);
|
||||
const handleAttributeValueReorder = createAttributeValueReorderHandler(
|
||||
attributes.change,
|
||||
attributes.data,
|
||||
triggerChange
|
||||
);
|
||||
|
||||
// Need to make it function to always have content.current up to date
|
||||
const getData = (): PageData => ({
|
||||
|
@ -190,6 +198,7 @@ function usePageForm(
|
|||
handlers: {
|
||||
changeContent,
|
||||
changeMetadata,
|
||||
reorderAttributeValue: handleAttributeValueReorder,
|
||||
selectAttribute: handleAttributeChange,
|
||||
selectAttributeFile: handleAttributeFileChange,
|
||||
selectAttributeMulti: handleAttributeMultiChange,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { AttributeInputData } from "@saleor/components/Attributes";
|
||||
import { FormChange } from "@saleor/hooks/useForm";
|
||||
import { FormsetChange, FormsetData } from "@saleor/hooks/useFormset";
|
||||
import { toggle } from "@saleor/utils/lists";
|
||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||
|
||||
import { PageDetails_page_pageType } from "../types/PageDetails";
|
||||
import { getAttributeInputFromPageType } from "./data";
|
||||
|
@ -23,34 +22,3 @@ export function createPageTypeSelectHandler(
|
|||
setAttributes(getAttributeInputFromPageType(selectedPageType));
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange {
|
||||
return (attributeId: string, value: string) => {
|
||||
triggerChange();
|
||||
changeAttributeData(attributeId, value === "" ? [] : [value]);
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeMultiChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
attributes: FormsetData<AttributeInputData, string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange {
|
||||
return (attributeId: string, value: string) => {
|
||||
const attribute = attributes.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
|
||||
const newAttributeValues = toggle(
|
||||
value,
|
||||
attribute.value,
|
||||
(a, b) => a === b
|
||||
);
|
||||
|
||||
triggerChange();
|
||||
changeAttributeData(attributeId, newAttributeValues);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -206,6 +206,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
|
|||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { OutputData } from "@editorjs/editorjs";
|
||||
import { getAttributesDisplayData } from "@saleor/attributes/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createAttributeValueReorderHandler
|
||||
} from "@saleor/attributes/utils/handlers";
|
||||
import { ChannelData, ChannelPriceArgs } from "@saleor/channels/utils";
|
||||
import {
|
||||
AttributeInput,
|
||||
|
@ -20,10 +27,6 @@ import {
|
|||
ProductType
|
||||
} from "@saleor/products/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createChannelsChangeHandler,
|
||||
createChannelsPriceChangeHandler,
|
||||
createProductTypeSelectHandler
|
||||
|
@ -35,6 +38,7 @@ import {
|
|||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { SearchProductTypes_search_edges_node } from "@saleor/searches/types/SearchProductTypes";
|
||||
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler";
|
||||
import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler";
|
||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||
|
@ -92,6 +96,7 @@ export interface ProductCreateHandlers
|
|||
>,
|
||||
Record<"selectAttributeReference", FormsetChange<string[]>>,
|
||||
Record<"selectAttributeFile", FormsetChange<File>>,
|
||||
Record<"reorderAttributeValue", FormsetChange<ReorderEvent>>,
|
||||
Record<"addStock" | "deleteStock", (id: string) => void> {
|
||||
changeDescription: RichTextEditorChange;
|
||||
}
|
||||
|
@ -224,6 +229,11 @@ function useProductCreateForm(
|
|||
attributesWithNewFileValue.change,
|
||||
triggerChange
|
||||
);
|
||||
const handleAttributeValueReorder = createAttributeValueReorderHandler(
|
||||
attributes.change,
|
||||
attributes.data,
|
||||
triggerChange
|
||||
);
|
||||
const handleProductTypeSelect = createProductTypeSelectHandler(
|
||||
attributes.set,
|
||||
setProductType,
|
||||
|
@ -305,6 +315,7 @@ function useProductCreateForm(
|
|||
changeMetadata,
|
||||
changeStock: handleStockChange,
|
||||
deleteStock: handleStockDelete,
|
||||
reorderAttributeValue: handleAttributeValueReorder,
|
||||
selectAttribute: handleAttributeChange,
|
||||
selectAttributeFile: handleAttributeFileChange,
|
||||
selectAttributeMultiple: handleAttributeMultiChange,
|
||||
|
|
|
@ -267,6 +267,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
|
|||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
)}
|
||||
<CardSpacer />
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { OutputData } from "@editorjs/editorjs";
|
||||
import { getAttributesDisplayData } from "@saleor/attributes/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createAttributeValueReorderHandler
|
||||
} from "@saleor/attributes/utils/handlers";
|
||||
import { ChannelData, ChannelPriceArgs } from "@saleor/channels/utils";
|
||||
import { AttributeInput } from "@saleor/components/Attributes";
|
||||
import { MetadataFormData } from "@saleor/components/Metadata";
|
||||
|
@ -19,10 +26,6 @@ import {
|
|||
getStockInputFromProduct
|
||||
} from "@saleor/products/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createChannelsChangeHandler,
|
||||
createChannelsPriceChangeHandler
|
||||
} from "@saleor/products/utils/handlers";
|
||||
|
@ -32,6 +35,7 @@ import {
|
|||
} from "@saleor/products/utils/validation";
|
||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
|
||||
import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler";
|
||||
import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler";
|
||||
|
@ -109,6 +113,7 @@ export interface ProductUpdateHandlers
|
|||
>,
|
||||
Record<"selectAttributeReference", FormsetChange<string[]>>,
|
||||
Record<"selectAttributeFile", FormsetChange<File>>,
|
||||
Record<"reorderAttributeValue", FormsetChange<ReorderEvent>>,
|
||||
Record<"addStock" | "deleteStock", (id: string) => void> {
|
||||
changeDescription: RichTextEditorChange;
|
||||
}
|
||||
|
@ -234,6 +239,11 @@ function useProductUpdateForm(
|
|||
attributesWithNewFileValue.change,
|
||||
triggerChange
|
||||
);
|
||||
const handleAttributeValueReorder = createAttributeValueReorderHandler(
|
||||
attributes.change,
|
||||
attributes.data,
|
||||
triggerChange
|
||||
);
|
||||
const handleStockChange: FormsetChange<string> = (id, value) => {
|
||||
triggerChange();
|
||||
stocks.change(id, value);
|
||||
|
@ -322,6 +332,7 @@ function useProductUpdateForm(
|
|||
changeMetadata,
|
||||
changeStock: handleStockChange,
|
||||
deleteStock: handleStockDelete,
|
||||
reorderAttributeValue: handleAttributeValueReorder,
|
||||
selectAttribute: handleAttributeChange,
|
||||
selectAttributeFile: handleAttributeFileChange,
|
||||
selectAttributeMultiple: handleAttributeMultiChange,
|
||||
|
|
|
@ -162,6 +162,9 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
|
|||
onChange={handlers.selectAttribute}
|
||||
onMultiChange={handlers.selectAttributeMultiple}
|
||||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<Attributes
|
||||
|
@ -179,6 +182,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
|
|||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<ProductShipping
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
import { getAttributesDisplayData } from "@saleor/attributes/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createAttributeValueReorderHandler
|
||||
} from "@saleor/attributes/utils/handlers";
|
||||
import { ChannelPriceData, IChannelPriceArgs } from "@saleor/channels/utils";
|
||||
import { AttributeInput } from "@saleor/components/Attributes";
|
||||
import { MetadataFormData } from "@saleor/components/Metadata";
|
||||
|
@ -9,21 +16,14 @@ import useFormset, {
|
|||
} from "@saleor/hooks/useFormset";
|
||||
import { ProductVariantCreateData_product } from "@saleor/products/types/ProductVariantCreateData";
|
||||
import { getVariantAttributeInputFromProduct } from "@saleor/products/utils/data";
|
||||
import {
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
getChannelsInput
|
||||
} from "@saleor/products/utils/handlers";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeMultiChangeHandler
|
||||
} from "@saleor/products/utils/handlers";
|
||||
import { getChannelsInput } from "@saleor/products/utils/handlers";
|
||||
import {
|
||||
validateCostPrice,
|
||||
validatePrice
|
||||
} from "@saleor/products/utils/validation";
|
||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||
import React from "react";
|
||||
|
||||
|
@ -57,6 +57,7 @@ export interface ProductVariantCreateHandlers
|
|||
>,
|
||||
Record<"selectAttributeReference", FormsetChange<string[]>>,
|
||||
Record<"selectAttributeFile", FormsetChange<File>>,
|
||||
Record<"reorderAttributeValue", FormsetChange<ReorderEvent>>,
|
||||
Record<"addStock" | "deleteStock", (id: string) => void> {
|
||||
changeMetadata: FormChange;
|
||||
}
|
||||
|
@ -131,6 +132,11 @@ function useProductVariantCreateForm(
|
|||
attributesWithNewFileValue.change,
|
||||
triggerChange
|
||||
);
|
||||
const handleAttributeValueReorder = createAttributeValueReorderHandler(
|
||||
attributes.change,
|
||||
attributes.data,
|
||||
triggerChange
|
||||
);
|
||||
const handleStockAdd = (id: string) => {
|
||||
triggerChange();
|
||||
stocks.add({
|
||||
|
@ -183,6 +189,7 @@ function useProductVariantCreateForm(
|
|||
changeMetadata,
|
||||
changeStock: handleStockChange,
|
||||
deleteStock: handleStockDelete,
|
||||
reorderAttributeValue: handleAttributeValueReorder,
|
||||
selectAttribute: handleAttributeChange,
|
||||
selectAttributeFile: handleAttributeFileChange,
|
||||
selectAttributeMultiple: handleAttributeMultiChange,
|
||||
|
|
|
@ -217,6 +217,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
|||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<Attributes
|
||||
|
@ -236,6 +237,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
|
|||
onFileChange={handlers.selectAttributeFile}
|
||||
onReferencesRemove={handlers.selectAttributeReference}
|
||||
onReferencesAddClick={onAssignReferencesClick}
|
||||
onReferencesReorder={handlers.reorderAttributeValue}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<ProductVariantImages
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
import { getAttributesDisplayData } from "@saleor/attributes/utils/data";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeMultiChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
createAttributeValueReorderHandler
|
||||
} from "@saleor/attributes/utils/handlers";
|
||||
import { ChannelPriceData, IChannelPriceArgs } from "@saleor/channels/utils";
|
||||
import { AttributeInput } from "@saleor/components/Attributes";
|
||||
import { MetadataFormData } from "@saleor/components/Metadata";
|
||||
|
@ -12,21 +19,14 @@ import {
|
|||
getAttributeInputFromVariant,
|
||||
getStockInputFromVariant
|
||||
} from "@saleor/products/utils/data";
|
||||
import {
|
||||
createAttributeFileChangeHandler,
|
||||
createAttributeReferenceChangeHandler,
|
||||
getChannelsInput
|
||||
} from "@saleor/products/utils/handlers";
|
||||
import {
|
||||
createAttributeChangeHandler,
|
||||
createAttributeMultiChangeHandler
|
||||
} from "@saleor/products/utils/handlers";
|
||||
import { getChannelsInput } from "@saleor/products/utils/handlers";
|
||||
import {
|
||||
validateCostPrice,
|
||||
validatePrice
|
||||
} from "@saleor/products/utils/validation";
|
||||
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
||||
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import { mapMetadataItemToInput } from "@saleor/utils/maps";
|
||||
import getMetadata from "@saleor/utils/metadata/getMetadata";
|
||||
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
||||
|
@ -72,6 +72,7 @@ export interface ProductVariantUpdateHandlers
|
|||
>,
|
||||
Record<"selectAttributeReference", FormsetChange<string[]>>,
|
||||
Record<"selectAttributeFile", FormsetChange<File>>,
|
||||
Record<"reorderAttributeValue", FormsetChange<ReorderEvent>>,
|
||||
Record<"addStock" | "deleteStock", (id: string) => void> {
|
||||
changeMetadata: FormChange;
|
||||
}
|
||||
|
@ -148,6 +149,11 @@ function useProductVariantUpdateForm(
|
|||
attributesWithNewFileValue.change,
|
||||
triggerChange
|
||||
);
|
||||
const handleAttributeValueReorder = createAttributeValueReorderHandler(
|
||||
attributes.change,
|
||||
attributes.data,
|
||||
triggerChange
|
||||
);
|
||||
const handleStockAdd = (id: string) => {
|
||||
triggerChange();
|
||||
stocks.add({
|
||||
|
@ -233,6 +239,7 @@ function useProductVariantUpdateForm(
|
|||
changeMetadata,
|
||||
changeStock: handleStockChange,
|
||||
deleteStock: handleStockDelete,
|
||||
reorderAttributeValue: handleAttributeValueReorder,
|
||||
selectAttribute: handleAttributeChange,
|
||||
selectAttributeFile: handleAttributeFileChange,
|
||||
selectAttributeMultiple: handleAttributeMultiChange,
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
import { AttributeInputData } from "@saleor/components/Attributes";
|
||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
|
||||
import { createAttributeMultiChangeHandler } from "./handlers";
|
||||
|
||||
const attributes: FormsetData<AttributeInputData, string[]> = [
|
||||
{
|
||||
data: {
|
||||
inputType: AttributeInputTypeEnum.DROPDOWN,
|
||||
isRequired: false,
|
||||
values: [
|
||||
{
|
||||
__typename: "AttributeValue",
|
||||
file: null,
|
||||
id: "attrv-1",
|
||||
name: "Attribute 1 Value 1",
|
||||
reference: null,
|
||||
slug: "attr-1-v-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
id: "attr-1",
|
||||
label: "Attribute 1",
|
||||
value: []
|
||||
},
|
||||
{
|
||||
data: {
|
||||
inputType: AttributeInputTypeEnum.MULTISELECT,
|
||||
isRequired: false,
|
||||
values: [
|
||||
{
|
||||
__typename: "AttributeValue",
|
||||
file: null,
|
||||
id: "attrv-2",
|
||||
name: "Attribute 2 Value 1",
|
||||
reference: null,
|
||||
slug: "attr-2-v-1"
|
||||
},
|
||||
{
|
||||
__typename: "AttributeValue",
|
||||
file: null,
|
||||
id: "attrv-3",
|
||||
name: "Attribute 2 Value 2",
|
||||
reference: null,
|
||||
slug: "attr-2-v-2"
|
||||
},
|
||||
{
|
||||
__typename: "AttributeValue",
|
||||
file: null,
|
||||
id: "attrv-4",
|
||||
name: "Attribute 2 Value 3",
|
||||
reference: null,
|
||||
slug: "attr-2-v-3"
|
||||
}
|
||||
]
|
||||
},
|
||||
id: "attr-2",
|
||||
label: "Attribute 2",
|
||||
value: ["attr-2-v-3"]
|
||||
},
|
||||
{
|
||||
data: {
|
||||
inputType: AttributeInputTypeEnum.FILE,
|
||||
isRequired: false,
|
||||
values: [
|
||||
{
|
||||
__typename: "AttributeValue",
|
||||
file: {
|
||||
__typename: "File",
|
||||
contentType: "image/png",
|
||||
url: "some-non-existing-url"
|
||||
},
|
||||
id: "attrv-5",
|
||||
name: "File First Value",
|
||||
reference: null,
|
||||
slug: "file-first-value"
|
||||
}
|
||||
]
|
||||
},
|
||||
id: "attr-3",
|
||||
label: "File Attribute",
|
||||
value: []
|
||||
}
|
||||
];
|
||||
|
||||
describe("Multiple select", () => {
|
||||
it("is able to select value", () => {
|
||||
const change = jest.fn();
|
||||
const trigger = jest.fn();
|
||||
const handler = createAttributeMultiChangeHandler(
|
||||
change,
|
||||
attributes,
|
||||
trigger
|
||||
);
|
||||
|
||||
handler("attr-2", "attr-2-v-1");
|
||||
|
||||
expect(change).toHaveBeenCalledTimes(1);
|
||||
expect(change.mock.calls[0][0]).toBe("attr-2");
|
||||
expect(change.mock.calls[0][1]).toHaveLength(2);
|
||||
expect(change.mock.calls[0][1][0]).toBe("attr-2-v-3");
|
||||
expect(change.mock.calls[0][1][1]).toBe("attr-2-v-1");
|
||||
expect(trigger).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("is able to deselect value", () => {
|
||||
const change = jest.fn();
|
||||
const trigger = jest.fn();
|
||||
const handler = createAttributeMultiChangeHandler(
|
||||
change,
|
||||
attributes,
|
||||
trigger
|
||||
);
|
||||
|
||||
handler("attr-2", "attr-2-v-3");
|
||||
|
||||
expect(change).toHaveBeenCalledTimes(1);
|
||||
expect(change.mock.calls[0][0]).toBe("attr-2");
|
||||
expect(change.mock.calls[0][1]).toHaveLength(0);
|
||||
expect(trigger).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("is able to add custom value", () => {
|
||||
const change = jest.fn();
|
||||
const trigger = jest.fn();
|
||||
const handler = createAttributeMultiChangeHandler(
|
||||
change,
|
||||
attributes,
|
||||
trigger
|
||||
);
|
||||
|
||||
handler("attr-2", "A Value");
|
||||
|
||||
expect(change).toHaveBeenCalledTimes(1);
|
||||
expect(change.mock.calls[0][0]).toBe("attr-2");
|
||||
expect(change.mock.calls[0][1]).toHaveLength(2);
|
||||
expect(change.mock.calls[0][1][0]).toBe("attr-2-v-3");
|
||||
expect(change.mock.calls[0][1][1]).toBe("A Value");
|
||||
expect(trigger).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -5,25 +5,10 @@ import {
|
|||
} from "@saleor/channels/utils";
|
||||
import { AttributeInputData } from "@saleor/components/Attributes";
|
||||
import { FormChange } from "@saleor/hooks/useForm";
|
||||
import {
|
||||
FormsetAtomicData,
|
||||
FormsetChange,
|
||||
FormsetData
|
||||
} from "@saleor/hooks/useFormset";
|
||||
import { toggle } from "@saleor/utils/lists";
|
||||
import { FormsetData } from "@saleor/hooks/useFormset";
|
||||
|
||||
import { getAttributeInputFromProductType, ProductType } from "./data";
|
||||
|
||||
export function createAttributeChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<string> {
|
||||
return (attributeId: string, value: string) => {
|
||||
triggerChange();
|
||||
changeAttributeData(attributeId, value === "" ? [] : [value]);
|
||||
};
|
||||
}
|
||||
|
||||
export function createChannelsPriceChangeHandler(
|
||||
channelListings: ChannelPriceData[],
|
||||
updateChannels: (data: ChannelPriceData[]) => void,
|
||||
|
@ -103,66 +88,6 @@ export function createVariantChannelsChangeHandler(
|
|||
};
|
||||
}
|
||||
|
||||
export function createAttributeMultiChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
attributes: FormsetData<AttributeInputData, string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<string> {
|
||||
return (attributeId: string, value: string) => {
|
||||
const attribute = attributes.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
|
||||
const newAttributeValues = toggle(
|
||||
value,
|
||||
attribute.value,
|
||||
(a, b) => a === b
|
||||
);
|
||||
|
||||
triggerChange();
|
||||
changeAttributeData(attributeId, newAttributeValues);
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeReferenceChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<string[]> {
|
||||
return (attributeId: string, values: string[]) => {
|
||||
changeAttributeData(attributeId, values);
|
||||
triggerChange();
|
||||
};
|
||||
}
|
||||
|
||||
export function createAttributeFileChangeHandler(
|
||||
changeAttributeData: FormsetChange<string[]>,
|
||||
attributesWithNewFileValue: FormsetData<FormsetData<null, File>>,
|
||||
addAttributeNewFileValue: (data: FormsetAtomicData<null, File>) => void,
|
||||
changeAttributeNewFileValue: FormsetChange<File>,
|
||||
triggerChange: () => void
|
||||
): FormsetChange<File> {
|
||||
return (attributeId: string, value: File) => {
|
||||
triggerChange();
|
||||
|
||||
const newFileValueAssigned = attributesWithNewFileValue.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
|
||||
if (newFileValueAssigned) {
|
||||
changeAttributeNewFileValue(attributeId, value);
|
||||
} else {
|
||||
addAttributeNewFileValue({
|
||||
data: null,
|
||||
id: attributeId,
|
||||
label: null,
|
||||
value
|
||||
});
|
||||
}
|
||||
|
||||
changeAttributeData(attributeId, value ? [value.name] : []);
|
||||
};
|
||||
}
|
||||
|
||||
export function createProductTypeSelectHandler(
|
||||
setAttributes: (data: FormsetData<AttributeInputData>) => void,
|
||||
setProductType: (productType: ProductType) => void,
|
||||
|
|
|
@ -11234,6 +11234,389 @@ exports[`Storyshots Generics / Sortable chips field loading 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots Generics / Sortable chips field with error 1`] = `
|
||||
<div
|
||||
style="padding:24px"
|
||||
>
|
||||
<div
|
||||
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
|
||||
style="margin:auto;overflow:visible;position:relative;width:400px"
|
||||
>
|
||||
<div
|
||||
class="MuiCardContent-root-id"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="SortableChip-root-id SortableChipsField-chip-id"
|
||||
>
|
||||
<div
|
||||
class="SortableChip-content-id"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableHandle-drag-id SortableChip-sortableHandle-id"
|
||||
data-test="button-drag-handle"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2C3.5 2.82843 2.82843 3.5 2 3.5C1.17157 3.5 0.5 2.82843 0.5 2C0.5 1.17157 1.17157 0.5 2 0.5C2.82843 0.5 3.5 1.17157 3.5 2ZM4 2C4 3.10457 3.10457 4 2 4C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0C3.10457 0 4 0.895431 4 2ZM9.5 2C9.5 2.82843 8.82843 3.5 8 3.5C7.17157 3.5 6.5 2.82843 6.5 2C6.5 1.17157 7.17157 0.5 8 0.5C8.82843 0.5 9.5 1.17157 9.5 2ZM10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.895431 6.89543 0 8 0C9.10457 0 10 0.895431 10 2ZM8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10ZM3.5 8C3.5 8.82843 2.82843 9.5 2 9.5C1.17157 9.5 0.5 8.82843 0.5 8C0.5 7.17157 1.17157 6.5 2 6.5C2.82843 6.5 3.5 7.17157 3.5 8ZM4 8C4 9.10457 3.10457 10 2 10C0.895431 10 0 9.10457 0 8C0 6.89543 0.895431 6 2 6C3.10457 6 4 6.89543 4 8ZM2 15.5C2.82843 15.5 3.5 14.8284 3.5 14C3.5 13.1716 2.82843 12.5 2 12.5C1.17157 12.5 0.5 13.1716 0.5 14C0.5 14.8284 1.17157 15.5 2 15.5ZM2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 0 12.8954 0 14C0 15.1046 0.895431 16 2 16ZM9.5 14C9.5 14.8284 8.82843 15.5 8 15.5C7.17157 15.5 6.5 14.8284 6.5 14C6.5 13.1716 7.17157 12.5 8 12.5C8.82843 12.5 9.5 13.1716 9.5 14ZM10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z"
|
||||
fill="url(#paint0_linear)"
|
||||
fill-rule="evenodd"
|
||||
style="transform:translate(7px, 4px)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint0_linear"
|
||||
x1="0"
|
||||
x2="16.0896"
|
||||
y1="0"
|
||||
y2="10.4478"
|
||||
>
|
||||
<stop
|
||||
stop-color="#06847B"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3EE7CD"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="MuiTypography-root-id MuiTypography-body1-id"
|
||||
data-test="chip-label"
|
||||
>
|
||||
Item 1
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableChip-closeIcon-id"
|
||||
data-test="button-close"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="SortableChip-root-id SortableChipsField-chip-id"
|
||||
>
|
||||
<div
|
||||
class="SortableChip-content-id"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableHandle-drag-id SortableChip-sortableHandle-id"
|
||||
data-test="button-drag-handle"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2C3.5 2.82843 2.82843 3.5 2 3.5C1.17157 3.5 0.5 2.82843 0.5 2C0.5 1.17157 1.17157 0.5 2 0.5C2.82843 0.5 3.5 1.17157 3.5 2ZM4 2C4 3.10457 3.10457 4 2 4C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0C3.10457 0 4 0.895431 4 2ZM9.5 2C9.5 2.82843 8.82843 3.5 8 3.5C7.17157 3.5 6.5 2.82843 6.5 2C6.5 1.17157 7.17157 0.5 8 0.5C8.82843 0.5 9.5 1.17157 9.5 2ZM10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.895431 6.89543 0 8 0C9.10457 0 10 0.895431 10 2ZM8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10ZM3.5 8C3.5 8.82843 2.82843 9.5 2 9.5C1.17157 9.5 0.5 8.82843 0.5 8C0.5 7.17157 1.17157 6.5 2 6.5C2.82843 6.5 3.5 7.17157 3.5 8ZM4 8C4 9.10457 3.10457 10 2 10C0.895431 10 0 9.10457 0 8C0 6.89543 0.895431 6 2 6C3.10457 6 4 6.89543 4 8ZM2 15.5C2.82843 15.5 3.5 14.8284 3.5 14C3.5 13.1716 2.82843 12.5 2 12.5C1.17157 12.5 0.5 13.1716 0.5 14C0.5 14.8284 1.17157 15.5 2 15.5ZM2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 0 12.8954 0 14C0 15.1046 0.895431 16 2 16ZM9.5 14C9.5 14.8284 8.82843 15.5 8 15.5C7.17157 15.5 6.5 14.8284 6.5 14C6.5 13.1716 7.17157 12.5 8 12.5C8.82843 12.5 9.5 13.1716 9.5 14ZM10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z"
|
||||
fill="url(#paint0_linear)"
|
||||
fill-rule="evenodd"
|
||||
style="transform:translate(7px, 4px)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint0_linear"
|
||||
x1="0"
|
||||
x2="16.0896"
|
||||
y1="0"
|
||||
y2="10.4478"
|
||||
>
|
||||
<stop
|
||||
stop-color="#06847B"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3EE7CD"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="MuiTypography-root-id MuiTypography-body1-id"
|
||||
data-test="chip-label"
|
||||
>
|
||||
Item 2
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableChip-closeIcon-id"
|
||||
data-test="button-close"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="SortableChip-root-id SortableChipsField-chip-id"
|
||||
>
|
||||
<div
|
||||
class="SortableChip-content-id"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableHandle-drag-id SortableChip-sortableHandle-id"
|
||||
data-test="button-drag-handle"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2C3.5 2.82843 2.82843 3.5 2 3.5C1.17157 3.5 0.5 2.82843 0.5 2C0.5 1.17157 1.17157 0.5 2 0.5C2.82843 0.5 3.5 1.17157 3.5 2ZM4 2C4 3.10457 3.10457 4 2 4C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0C3.10457 0 4 0.895431 4 2ZM9.5 2C9.5 2.82843 8.82843 3.5 8 3.5C7.17157 3.5 6.5 2.82843 6.5 2C6.5 1.17157 7.17157 0.5 8 0.5C8.82843 0.5 9.5 1.17157 9.5 2ZM10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.895431 6.89543 0 8 0C9.10457 0 10 0.895431 10 2ZM8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10ZM3.5 8C3.5 8.82843 2.82843 9.5 2 9.5C1.17157 9.5 0.5 8.82843 0.5 8C0.5 7.17157 1.17157 6.5 2 6.5C2.82843 6.5 3.5 7.17157 3.5 8ZM4 8C4 9.10457 3.10457 10 2 10C0.895431 10 0 9.10457 0 8C0 6.89543 0.895431 6 2 6C3.10457 6 4 6.89543 4 8ZM2 15.5C2.82843 15.5 3.5 14.8284 3.5 14C3.5 13.1716 2.82843 12.5 2 12.5C1.17157 12.5 0.5 13.1716 0.5 14C0.5 14.8284 1.17157 15.5 2 15.5ZM2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 0 12.8954 0 14C0 15.1046 0.895431 16 2 16ZM9.5 14C9.5 14.8284 8.82843 15.5 8 15.5C7.17157 15.5 6.5 14.8284 6.5 14C6.5 13.1716 7.17157 12.5 8 12.5C8.82843 12.5 9.5 13.1716 9.5 14ZM10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z"
|
||||
fill="url(#paint0_linear)"
|
||||
fill-rule="evenodd"
|
||||
style="transform:translate(7px, 4px)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint0_linear"
|
||||
x1="0"
|
||||
x2="16.0896"
|
||||
y1="0"
|
||||
y2="10.4478"
|
||||
>
|
||||
<stop
|
||||
stop-color="#06847B"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3EE7CD"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="MuiTypography-root-id MuiTypography-body1-id"
|
||||
data-test="chip-label"
|
||||
>
|
||||
Item 3
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableChip-closeIcon-id"
|
||||
data-test="button-close"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="SortableChip-root-id SortableChipsField-chip-id"
|
||||
>
|
||||
<div
|
||||
class="SortableChip-content-id"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableHandle-drag-id SortableChip-sortableHandle-id"
|
||||
data-test="button-drag-handle"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2C3.5 2.82843 2.82843 3.5 2 3.5C1.17157 3.5 0.5 2.82843 0.5 2C0.5 1.17157 1.17157 0.5 2 0.5C2.82843 0.5 3.5 1.17157 3.5 2ZM4 2C4 3.10457 3.10457 4 2 4C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0C3.10457 0 4 0.895431 4 2ZM9.5 2C9.5 2.82843 8.82843 3.5 8 3.5C7.17157 3.5 6.5 2.82843 6.5 2C6.5 1.17157 7.17157 0.5 8 0.5C8.82843 0.5 9.5 1.17157 9.5 2ZM10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.895431 6.89543 0 8 0C9.10457 0 10 0.895431 10 2ZM8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10ZM3.5 8C3.5 8.82843 2.82843 9.5 2 9.5C1.17157 9.5 0.5 8.82843 0.5 8C0.5 7.17157 1.17157 6.5 2 6.5C2.82843 6.5 3.5 7.17157 3.5 8ZM4 8C4 9.10457 3.10457 10 2 10C0.895431 10 0 9.10457 0 8C0 6.89543 0.895431 6 2 6C3.10457 6 4 6.89543 4 8ZM2 15.5C2.82843 15.5 3.5 14.8284 3.5 14C3.5 13.1716 2.82843 12.5 2 12.5C1.17157 12.5 0.5 13.1716 0.5 14C0.5 14.8284 1.17157 15.5 2 15.5ZM2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 0 12.8954 0 14C0 15.1046 0.895431 16 2 16ZM9.5 14C9.5 14.8284 8.82843 15.5 8 15.5C7.17157 15.5 6.5 14.8284 6.5 14C6.5 13.1716 7.17157 12.5 8 12.5C8.82843 12.5 9.5 13.1716 9.5 14ZM10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z"
|
||||
fill="url(#paint0_linear)"
|
||||
fill-rule="evenodd"
|
||||
style="transform:translate(7px, 4px)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint0_linear"
|
||||
x1="0"
|
||||
x2="16.0896"
|
||||
y1="0"
|
||||
y2="10.4478"
|
||||
>
|
||||
<stop
|
||||
stop-color="#06847B"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3EE7CD"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="MuiTypography-root-id MuiTypography-body1-id"
|
||||
data-test="chip-label"
|
||||
>
|
||||
Item 4
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableChip-closeIcon-id"
|
||||
data-test="button-close"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="SortableChip-root-id SortableChipsField-chip-id"
|
||||
>
|
||||
<div
|
||||
class="SortableChip-content-id"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableHandle-drag-id SortableChip-sortableHandle-id"
|
||||
data-test="button-drag-handle"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2C3.5 2.82843 2.82843 3.5 2 3.5C1.17157 3.5 0.5 2.82843 0.5 2C0.5 1.17157 1.17157 0.5 2 0.5C2.82843 0.5 3.5 1.17157 3.5 2ZM4 2C4 3.10457 3.10457 4 2 4C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0C3.10457 0 4 0.895431 4 2ZM9.5 2C9.5 2.82843 8.82843 3.5 8 3.5C7.17157 3.5 6.5 2.82843 6.5 2C6.5 1.17157 7.17157 0.5 8 0.5C8.82843 0.5 9.5 1.17157 9.5 2ZM10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.895431 6.89543 0 8 0C9.10457 0 10 0.895431 10 2ZM8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10ZM3.5 8C3.5 8.82843 2.82843 9.5 2 9.5C1.17157 9.5 0.5 8.82843 0.5 8C0.5 7.17157 1.17157 6.5 2 6.5C2.82843 6.5 3.5 7.17157 3.5 8ZM4 8C4 9.10457 3.10457 10 2 10C0.895431 10 0 9.10457 0 8C0 6.89543 0.895431 6 2 6C3.10457 6 4 6.89543 4 8ZM2 15.5C2.82843 15.5 3.5 14.8284 3.5 14C3.5 13.1716 2.82843 12.5 2 12.5C1.17157 12.5 0.5 13.1716 0.5 14C0.5 14.8284 1.17157 15.5 2 15.5ZM2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 0 12.8954 0 14C0 15.1046 0.895431 16 2 16ZM9.5 14C9.5 14.8284 8.82843 15.5 8 15.5C7.17157 15.5 6.5 14.8284 6.5 14C6.5 13.1716 7.17157 12.5 8 12.5C8.82843 12.5 9.5 13.1716 9.5 14ZM10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z"
|
||||
fill="url(#paint0_linear)"
|
||||
fill-rule="evenodd"
|
||||
style="transform:translate(7px, 4px)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint0_linear"
|
||||
x1="0"
|
||||
x2="16.0896"
|
||||
y1="0"
|
||||
y2="10.4478"
|
||||
>
|
||||
<stop
|
||||
stop-color="#06847B"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3EE7CD"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="MuiTypography-root-id MuiTypography-body1-id"
|
||||
data-test="chip-label"
|
||||
>
|
||||
Item 5
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableChip-closeIcon-id"
|
||||
data-test="button-close"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="SortableChip-root-id SortableChipsField-chip-id"
|
||||
>
|
||||
<div
|
||||
class="SortableChip-content-id"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableHandle-drag-id SortableChip-sortableHandle-id"
|
||||
data-test="button-drag-handle"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M3.5 2C3.5 2.82843 2.82843 3.5 2 3.5C1.17157 3.5 0.5 2.82843 0.5 2C0.5 1.17157 1.17157 0.5 2 0.5C2.82843 0.5 3.5 1.17157 3.5 2ZM4 2C4 3.10457 3.10457 4 2 4C0.895431 4 0 3.10457 0 2C0 0.895431 0.895431 0 2 0C3.10457 0 4 0.895431 4 2ZM9.5 2C9.5 2.82843 8.82843 3.5 8 3.5C7.17157 3.5 6.5 2.82843 6.5 2C6.5 1.17157 7.17157 0.5 8 0.5C8.82843 0.5 9.5 1.17157 9.5 2ZM10 2C10 3.10457 9.10457 4 8 4C6.89543 4 6 3.10457 6 2C6 0.895431 6.89543 0 8 0C9.10457 0 10 0.895431 10 2ZM8 9.5C8.82843 9.5 9.5 8.82843 9.5 8C9.5 7.17157 8.82843 6.5 8 6.5C7.17157 6.5 6.5 7.17157 6.5 8C6.5 8.82843 7.17157 9.5 8 9.5ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10ZM3.5 8C3.5 8.82843 2.82843 9.5 2 9.5C1.17157 9.5 0.5 8.82843 0.5 8C0.5 7.17157 1.17157 6.5 2 6.5C2.82843 6.5 3.5 7.17157 3.5 8ZM4 8C4 9.10457 3.10457 10 2 10C0.895431 10 0 9.10457 0 8C0 6.89543 0.895431 6 2 6C3.10457 6 4 6.89543 4 8ZM2 15.5C2.82843 15.5 3.5 14.8284 3.5 14C3.5 13.1716 2.82843 12.5 2 12.5C1.17157 12.5 0.5 13.1716 0.5 14C0.5 14.8284 1.17157 15.5 2 15.5ZM2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 0 12.8954 0 14C0 15.1046 0.895431 16 2 16ZM9.5 14C9.5 14.8284 8.82843 15.5 8 15.5C7.17157 15.5 6.5 14.8284 6.5 14C6.5 13.1716 7.17157 12.5 8 12.5C8.82843 12.5 9.5 13.1716 9.5 14ZM10 14C10 15.1046 9.10457 16 8 16C6.89543 16 6 15.1046 6 14C6 12.8954 6.89543 12 8 12C9.10457 12 10 12.8954 10 14Z"
|
||||
fill="url(#paint0_linear)"
|
||||
fill-rule="evenodd"
|
||||
style="transform:translate(7px, 4px)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="paint0_linear"
|
||||
x1="0"
|
||||
x2="16.0896"
|
||||
y1="0"
|
||||
y2="10.4478"
|
||||
>
|
||||
<stop
|
||||
stop-color="#06847B"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#3EE7CD"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="MuiTypography-root-id MuiTypography-body1-id"
|
||||
data-test="chip-label"
|
||||
>
|
||||
Item 6
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root-id SortableChip-closeIcon-id"
|
||||
data-test="button-close"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="MuiTypography-root-id SortableChipsField-errorText-id MuiTypography-caption-id"
|
||||
>
|
||||
Something went wrong
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots Generics / Square Button default 1`] = `
|
||||
<div
|
||||
style="padding:24px"
|
||||
|
|
Loading…
Reference in a new issue