Create Product Block
The CreateProduct Component is a fully customizable and accessible product creation form built with React and TypeScript. It provides a complete interface for product registration with image upload, category selection, location information, and modern design patterns.
π Installationβ
npm install @nodeblocks/frontend-create-product-block
π Usageβ
import {CreateProduct} from '@nodeblocks/frontend-create-product-block';
- Basic Usage
- Advanced Usage
function BasicCreateProduct() { const categoryOptions = [ { value: 'electronics', label: 'Electronics' }, { value: 'clothing', label: 'Clothing' }, { value: 'home', label: 'Home & Garden' } ]; return ( <CreateProduct categoryOptions={categoryOptions} onSubmit={(formData) => { console.log('Product created:', formData); }} onChange={(setError, getValues, clearErrors) => { const values = getValues(); console.log('Form values:', values); }} onAcceptAttachment={(files) => { console.log('File accepted:', files); }} onUploadAttachment={(file) => { console.log('Uploading file:', file); // Handle file upload logic }} onClearAttachment={() => { console.log('Attachment cleared'); }}> <CreateProduct.MainInfo> <CreateProduct.MainInfo.SectionTitle>Product Information</CreateProduct.MainInfo.SectionTitle> <CreateProduct.MainInfo.Dropzone /> <CreateProduct.MainInfo.NameField /> </CreateProduct.MainInfo> <CreateProduct.BasicInfo> <CreateProduct.BasicInfo.Title /> <CreateProduct.BasicInfo.CategoryField /> <CreateProduct.BasicInfo.DescriptionField /> </CreateProduct.BasicInfo> <CreateProduct.AdditionalInfo> <CreateProduct.AdditionalInfo.Title /> <CreateProduct.AdditionalInfo.Subtitle /> <CreateProduct.AdditionalInfo.Address1Field /> <CreateProduct.AdditionalInfo.Address2Field /> </CreateProduct.AdditionalInfo> <CreateProduct.Actions> <CreateProduct.Actions.SubmitButton>Create Product</CreateProduct.Actions.SubmitButton> </CreateProduct.Actions> </CreateProduct> ); }
function AdvancedCreateProduct() { const categoryOptions = [ { value: 'electronics', label: 'Electronics' }, { value: 'clothing', label: 'Clothing' }, { value: 'home', label: 'Home & Garden' }, { value: 'sports', label: 'Sports & Outdoor' }, { value: 'automotive', label: 'Automotive' } ]; return ( <CreateProduct categoryOptions={categoryOptions} onSubmit={(formData) => { console.log('Advanced product created:', formData); }} onChange={(setError, getValues, clearErrors) => { const values = getValues(); console.log('Form validation:', values); }} onAcceptAttachment={(files) => { console.log('Files accepted:', files); }} onUploadAttachment={(file) => { console.log('Uploading:', file); }} onClearAttachment={() => { console.log('Attachment cleared'); }}> {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, // Override Main Info section with custom styling mainInfo: { ...defaultBlocks.mainInfo, props: { ...defaultBlocks.mainInfo.props, style: { background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', borderRadius: '16px', padding: '32px', color: 'white', marginBottom: '24px' } } }, // Override Basic Info section with enhanced styling basicInfo: { ...defaultBlocks.basicInfo, props: { ...defaultBlocks.basicInfo.props, style: { background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', borderRadius: '16px', padding: '28px', color: 'white', marginBottom: '24px', boxShadow: '0 10px 30px rgba(0,0,0,0.1)' } } }, // Full override of Additional Info section additionalInfo: ( <div style={{ background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', borderRadius: '16px', padding: '32px', color: 'white', marginBottom: '24px', boxShadow: '0 15px 35px rgba(0,0,0,0.1)' }}> <h3 style={{ fontSize: '24px', fontWeight: 'bold', marginBottom: '8px', background: 'linear-gradient(45deg, #ffffff, #e8f4f8)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent', backgroundClip: 'text' }}> π Product Location Details </h3> <p style={{ fontSize: '14px', marginBottom: '24px', opacity: 0.9 }}> Specify where your product is located for better visibility </p> <div style={{ display: 'grid', gap: '20px' }}> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.2)' }}> <CreateProduct.AdditionalInfo.Address1Field style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.2)' }}> <CreateProduct.AdditionalInfo.Address2Field style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> {/* Custom additional fields */} <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.2)' }}> <CreateProduct.TextField name="coordinates" label="GPS Coordinates (Optional)" placeholder="e.g., 35.6762, 139.6503" style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> </div> </div> ), // Enhanced actions section actions: { ...defaultBlocks.actions, props: { ...defaultBlocks.actions.props, style: { background: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)', padding: '24px', textAlign: 'center', boxShadow: '0 10px 30px rgba(0,0,0,0.15)' } } } }, blockOrder: defaultBlockOrder })} </CreateProduct> ); }
Example with Complete Form Override:
function CustomCreateProduct() { const categoryOptions = [ { value: 'premium', label: 'π Premium Products' }, { value: 'limited', label: 'β Limited Edition' }, { value: 'exclusive', label: 'π₯ Exclusive Items' } ]; return ( <CreateProduct categoryOptions={categoryOptions} onSubmit={(formData) => { console.log('Custom product created:', formData); }} onChange={(setError, getValues, clearErrors) => { console.log('Custom form validation:', getValues()); }} onAcceptAttachment={(files) => { console.log('Custom file handling:', files); }} onUploadAttachment={(file) => { console.log('Custom upload:', file); }} onClearAttachment={() => { console.log('Custom clear'); }}> {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { // Complete override of main info mainInfo: ( <div style={{ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', borderRadius: '20px', padding: '40px', color: 'white', marginBottom: '30px', position: 'relative', overflow: 'hidden' }}> <div style={{ position: 'absolute', top: '-50%', right: '-50%', width: '200%', height: '200%', background: 'radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%)', transform: 'rotate(45deg)' }}></div> <div style={{ position: 'relative', zIndex: 1 }}> <h2 style={{ fontSize: '28px', fontWeight: 'bold', marginBottom: '16px', display: 'flex', alignItems: 'center', gap: '12px' }}> π Product Showcase </h2> <p style={{ fontSize: '16px', marginBottom: '32px', opacity: 0.9 }}> Create an amazing product listing that stands out from the crowd </p> <div style={{ display: 'grid', gridTemplateColumns: '1fr 2fr', gap: '24px', alignItems: 'start' }}> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '16px', padding: '24px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', textAlign: 'center' }}> <CreateProduct.MainInfo.Dropzone beforeUploadMessage="πΈ Upload Image" beforeUploadSubtitle="Drag & drop or click to select" style={{ background: 'rgba(255,255,255,0.1)', border: '2px dashed rgba(255,255,255,0.3)', borderRadius: '12px' }} /> </div> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '16px', padding: '24px', backdropFilter: 'blur(10px)', border: '1px solid rgba(255,255,255,0.2)' }}> <CreateProduct.MainInfo.NameField label="β¨ Product Name" placeholder="Enter an amazing product name..." style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333', marginBottom: '20px' }} /> <CreateProduct.TextField name="subtitle" label="π Product Subtitle" placeholder="A catchy subtitle that describes your product" style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> </div> </div> </div> ), // Enhanced basic info with product features basicInfo: ( <div style={{ background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', borderRadius: '20px', padding: '32px', color: 'white', marginBottom: '30px' }}> <h3 style={{ fontSize: '24px', fontWeight: 'bold', marginBottom: '24px', display: 'flex', alignItems: 'center', gap: '12px' }}> π Product Details </h3> <div style={{ display: 'grid', gap: '24px' }}> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)' }}> <CreateProduct.BasicInfo.CategoryField style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)' }}> <CreateProduct.BasicInfo.DescriptionField placeholder="Describe your product's features, benefits, and what makes it special..." style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333', minHeight: '120px' }} /> </div> <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px' }}> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)' }}> <CreateProduct.TextField name="price" label="π° Price" placeholder="0.00" style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> <div style={{ background: 'rgba(255,255,255,0.15)', borderRadius: '12px', padding: '20px', backdropFilter: 'blur(10px)' }}> <CreateProduct.SelectField name="condition" label="π Condition" selectOptionValues={[ { value: 'new', label: 'Brand New' }, { value: 'excellent', label: 'Excellent' }, { value: 'good', label: 'Good' }, { value: 'fair', label: 'Fair' } ]} style={{ background: 'rgba(255,255,255,0.9)', borderRadius: '8px', color: '#333' }} /> </div> </div> </div> </div> ), // Keep enhanced additional info additionalInfo: defaultBlocks.additionalInfo, // Enhanced action buttons actions: ( <div style={{ background: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)', borderRadius: '20px', padding: '32px', textAlign: 'center', marginTop: '30px' }}> <div style={{ display: 'flex', gap: '16px', justifyContent: 'center', alignItems: 'center' }}> <button type="button" style={{ background: 'rgba(255,255,255,0.2)', border: '2px solid rgba(255,255,255,0.3)', borderRadius: '12px', padding: '12px 24px', color: 'white', fontSize: '16px', fontWeight: '600', cursor: 'pointer', backdropFilter: 'blur(10px)', transition: 'all 0.3s ease' }} onMouseOver={(e) => { e.target.style.background = 'rgba(255,255,255,0.3)'; e.target.style.transform = 'translateY(-2px)'; }} onMouseOut={(e) => { e.target.style.background = 'rgba(255,255,255,0.2)'; e.target.style.transform = 'translateY(0)'; }} > πΎ Save Draft </button> <CreateProduct.Actions.SubmitButton style={{ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', border: 'none', borderRadius: '12px', padding: '12px 32px', color: 'white', fontSize: '16px', fontWeight: '600', boxShadow: '0 6px 20px rgba(0,0,0,0.2)', transition: 'all 0.3s ease' }} > π Launch Product </CreateProduct.Actions.SubmitButton> <button type="button" style={{ background: 'rgba(255,255,255,0.2)', border: '2px solid rgba(255,255,255,0.3)', borderRadius: '12px', padding: '12px 24px', color: 'white', fontSize: '16px', fontWeight: '600', cursor: 'pointer', backdropFilter: 'blur(10px)', transition: 'all 0.3s ease' }} onMouseOver={(e) => { e.target.style.background = 'rgba(255,255,255,0.3)'; e.target.style.transform = 'translateY(-2px)'; }} onMouseOut={(e) => { e.target.style.background = 'rgba(255,255,255,0.2)'; e.target.style.transform = 'translateY(0)'; }} > ποΈ Preview </button> </div> </div> ) }, blockOrder: ['mainInfo', 'basicInfo', 'additionalInfo', 'actions'] })} </CreateProduct> ); }
π§ Props Referenceβ
Main Component Propsβ
Prop | Type | Default | Description |
---|---|---|---|
onSubmit | (data: T, event?: React.BaseSyntheticEvent) => void | Required | Callback function triggered when form is submitted with valid data |
onChange | (setError, getValues, clearErrors) => void | Required | Callback function triggered when form values change |
categoryOptions | OptionValue[] | undefined | Array of category options for the category select field |
onAcceptAttachment | (files: File[]) => void | undefined | Callback fired when file is accepted for upload |
onUploadAttachment | (file: File) => void | undefined | Callback fired when file upload is triggered |
onRejectAttachment | (files: File[]) => void | undefined | Callback fired when file is rejected |
onClearAttachment | () => void | undefined | Callback fired when attachment is cleared |
defaultData | DefaultValues<T> | undefined | Default form values to populate fields on initial render |
data | T | undefined | Controlled form values - use this for external form state management |
className | string | undefined | Additional CSS class name for styling the form container |
children | BlocksOverride | undefined | Custom block components to override default rendering |
Note: This component inherits all HTML div
element props.
Sub-Componentsβ
The CreateProduct component provides several sub-components. All sub-components receive their default values from the main component's context and can override these values through props.
CreateProduct.MainInfoβ
Container for main product information including image upload and product name.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | undefined | Custom content to override default main info fields |
direction | enum | "column" | Flex direction for action buttons |
alignItems | enum | "stretch" | Alignment of items in the container |
gapSize | enum | "S" | Gap between items in the container |
CreateProduct.MainInfo.SectionTitleβ
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | "Main Info" | Title content for the main info section |
size | enum | "L" | Typography size for the title |
type | enum | "heading" | Typography type |
color | enum | "low-emphasis" | Color theme for the title |
weight | enum | "bold" | Typography weight |
className | string | undefined | Additional CSS class name for styling |
CreateProduct.MainInfo.Dropzoneβ
Prop | Type | Default | Description |
---|---|---|---|
beforeUploadMessage | string | "Upload" | Message displayed before file upload |
beforeUploadSubtitle | string | "Select a file to upload." | Subtitle displayed before file upload |
afterUploadOptionsButton | string | "Options" | Text for options button after upload |
replaceFileButton | string | "Select a new file" | Text for replace file button |
deleteFileButton | string | "Delete" | Text for delete file button |
maxFiles | number | 1 | Maximum number of files allowed |
accept | string | "image/*" | File types accepted |
maxSize | number | 5242880 | Maximum file size in bytes (5MB) |
className | string | undefined | Additional CSS class name for styling |
CreateProduct.MainInfo.NameFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | "name" | Field name used for form data and validation |
label | string | "Name" | Field label displayed above the input |
labelWeight | enum | "regular" | Weight of the field label |
name | string | "applicationUserEmail" | Field name for form data |
className | string | undefined | Additional CSS class name for styling |
errorText | string | undefined | Error text for the input |
isDisabled | boolean | undefined | Whether the input is disabled |
isRequired | boolean | undefined | Whether the input is required |
onOperationClick | () => void | undefined | Operation onClick callback |
postfixText | string | undefined | Text to place after the component |
showPassword | boolean | undefined | Whether to show password |
Note: This component additional inherits some common HTML input
element props.
CreateProduct.BasicInfoβ
Container for basic product information including category and description.
Prop | Type | Default | Description |
---|---|---|---|
children | BlocksOverride | undefined | Custom content to override default basic info fields |
className | string | undefined | Additional CSS class name for styling |
direction | enum | "column" | Flex direction for action buttons |
alignItems | enum | "stretch" | Alignment of items in the container |
gapSize | enum | "S" | Gap between items in the container |
CreateProduct.BasicInfo.Titleβ
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | "Basic Information" | Title content for the basic info section |
size | enum | "L" | Typography size for the title |
type | enum | "heading" | Typography type |
color | enum | "low-emphasis" | Color theme for the title |
weight | enum | "bold" | Typography weight |
className | string | undefined | Additional CSS class name for styling |
CreateProduct.BasicInfo.CategoryFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | "categoryId" | Field name for form data |
label | string | "Categories" | Field label |
labelWeight | enum | "regular" | Label weight |
selectOptionValues | Array<{value: string, label: string}> | [] | Array of category options |
isRequired | boolean | undefined | Whether the field is required |
isDisabled | boolean | undefined | Whether the input is disabled |
errorText | string | undefined | Error text for the input |
className | string | undefined | Additional CSS class name for styling |
Note: This component additional inherits some common HTML select
element props.
CreateProduct.BasicInfo.DescriptionFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | "description" | Field name for form data |
label | string | "Description" | Label of the input field |
errorText | string | undefined | Error text for the input |
isDisabled | boolean | undefined | Whether the input is disabled |
isRequired | boolean | undefined | Whether the input is required |
labelWeight | `enum | ||
className | string | undefined | Additional CSS class name for styling |
Note: This component additional inherits some common HTML textarea
element props.
CreateProduct.AdditionalInfoβ
Container for additional product information including location details.
Prop | Type | Default | Description |
---|---|---|---|
children | BlocksOverride | undefined | Custom content to override default additional info fields |
className | string | undefined | Additional CSS class name for styling |
direction | enum | "column" | Flex direction for action buttons |
alignItems | enum | "stretch" | Alignment of items in the container |
gapSize | enum | "S" | Gap between items in the container |
CreateProduct.AdditionalInfo.Titleβ
Prop | Type | Default | Description |
---|---|---|---|
children | BlockReasOverride | "Additional Information" | Title content for the additional info section |
size | enum | "L" | Typography size for the title |
type | enum | "heading" | Typography type |
color | enum | "low-emphasis" | Color theme for the title |
weight | enum | "bold" | Typography weight |
className | string | undefined | Additional CSS class name for styling |
CreateProduct.AdditionalInfo.Subtitleβ
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | "Location" | Subtitle content for the location section |
size | enum | "S" | Typography size for the title |
type | enum | "heading" | Typography type |
color | enum | "low-emphasis" | Color theme for the title |
weight | enum | "regular" | Typography weight |
className | string | undefined | Additional CSS class name for styling |
CreateProduct.AdditionalInfo.Address1Fieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | "address1" | Field name for form data |
label | string | "Prefecture" | Field label |
labelWeight | enum | "regular" | Label weight |
selectOptionValues | Array<{value: string, label: string}> | [] | Array of prefecture options |
isRequired | boolean | undefined | Whether the field is required |
isDisabled | boolean | undefined | Whether the input is disabled |
errorText | string | undefined | Error text for the input |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML select
element props.
CreateProduct.AdditionalInfo.Address2Fieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | "address2" | Field name used for form data and validation |
label | string | "Town" | Field label displayed above the input |
labelWeight | enum | "regular" | Weight of the field label |
className | string | undefined | Additional CSS class name for styling |
errorText | string | undefined | Error text for the input |
isDisabled | boolean | undefined | Whether the input is disabled |
isRequired | boolean | undefined | Whether the input is required |
onOperationClick | () => void | undefined | Operation onClick callback |
postfixText | string | undefined | Text to place after the component |
showPassword | boolean | undefined | Whether to show password |
Note: This component additional inherits some common HTML input
element props.
CreateProduct.Actionsβ
Container for form action buttons.
Prop | Type | Default | Description |
---|---|---|---|
children | BlocksOverride | undefined | Custom content to override default action buttons |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML div
element props.
CreateProduct.Actions.SubmitButtonβ
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | "Submit" | Text to place inside the button |
className | string | undefined | Additional CSS class name for styling |
fill | enum | "fill" | Button fill style |
icon | enum | undefined | Optional icon for the left-hand side of the button |
iconColor | enum | undefined | Color for the left-hand side icon. When not provided, a default color for the fill type will be used. |
isDisabled | boolean | false | Whether the button is disabled and cannot be used |
onClick | function | undefined | Function to handle button click |
size | enum | "M" | Button vertical size |
textAlign | enum | "center" | Button icon and text positioning within the button |
textColor | enum | "default" | Button text color |
textEmphasis | boolean | false | Button text weight |
textSize | enum | "M" | Button text size |
type | enum | "submit" | Button purpose (affects html type) |
Note: This component additional inherits some common HTML button
element props.
Additional Field Componentsβ
The component also provides additional field types that can be used in custom forms:
CreateProduct.TextFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | Required | Field name for form data |
errorText | string | undefined | Error text for the input |
isDisabled | boolean | undefined | Whether the input is disabled |
isRequired | boolean | undefined | Whether the input is required |
label | string | Required | Label of the input field |
labelWeight | enum | "regular" | Label weight |
onOperationClick | () => void | undefined | Operation onClick callback |
postfixText | string | undefined | Text to place after the component |
showPassword | boolean | undefined | Whether to show password |
Note: This component additional inherits some common HTML input
element props.
CreateProduct.TimeFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | Required | Field name for form data |
label | string | Required | Label of the input field |
labelWeight | enum | "regular" | Label weight |
isRequired | boolean | undefined | Whether the input is required |
isDisabled | boolean | undefined | Whether the input is disabled |
errorText | string | undefined | Error text for the input |
className | string | undefined | Additional CSS class name for styling |
Note: This component additional inherits some common HTML input
element props.
CreateProduct.CheckboxFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | Required | Field name for form data |
label | string | Required | Checkbox label |
message | string | undefined | Checkbox description message |
showMessage | boolean | true | Whether to show the message |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML checkbox
element props.
CreateProduct.SelectFieldβ
Prop | Type | Default | Description |
---|---|---|---|
name | string | "required" | Field name for form data |
label | string | "Required" | Field label |
labelWeight | enum | "regular" | Label weight |
selectOptionValues | Array<{value: string, label: string}> | [] | Array of options |
isRequired | boolean | undefined | Whether the field is required |
isDisabled | boolean | undefined | Whether the input is disabled |
errorText | string | undefined | Error text for the input |
className | string | undefined | Additional CSS class name for styling |
Note: This component additional inherits some common HTML select
element props.
π§ TypeScript Supportβ
Full TypeScript support with comprehensive type definitions:
import {CreateProduct} from '@nodeblocks/frontend-create-product-block';
//in future we will not use react-hook-form, we will use our own form handling
import {UseFormClearErrors, UseFormGetValues, UseFormSetError} from 'react-hook-form';
interface CustomProductFormData extends Record<string, unknown> {
name: string;
description: string;
address1: string;
address2: string;
categoryId: string;
image: {url: string; type?: string; id?: string};
customField?: string;
}
const handleSubmit = (data: CustomProductFormData, event?: React.BaseSyntheticEvent) => {
// Type-safe form handling
console.log('Product data:', data);
console.log('Event:', event);
};
const handleChange = (
setError: UseFormSetError<CustomProductFormData>,
getValues: UseFormGetValues<CustomProductFormData>,
clearErrors: UseFormClearErrors<CustomProductFormData>,
) => {
const values = getValues();
// Validate form values and set errors if needed
if (!values.name) {
setError('name', {message: 'Product name is required'});
} else {
clearErrors('name');
}
};
const categoryOptions = [
{value: 'electronics', label: 'Electronics'},
{value: 'clothing', label: 'Clothing'},
{value: 'home', label: 'Home & Garden'},
];
const CreateProductForm = () => {
return (
<CreateProduct<CustomProductFormData>
onSubmit={handleSubmit}
onChange={handleChange}
categoryOptions={categoryOptions}
onAcceptAttachment={files => console.log('Files accepted:', files)}
onUploadAttachment={file => console.log('Uploading:', file)}
onClearAttachment={() => console.log('Attachment cleared')}>
<CreateProduct.MainInfo>
<CreateProduct.MainInfo.SectionTitle>Product Details</CreateProduct.MainInfo.SectionTitle>
<CreateProduct.MainInfo.Dropzone />
<CreateProduct.MainInfo.NameField name="name" />
</CreateProduct.MainInfo>
<CreateProduct.BasicInfo>
<CreateProduct.BasicInfo.Title />
<CreateProduct.BasicInfo.CategoryField />
<CreateProduct.BasicInfo.DescriptionField />
</CreateProduct.BasicInfo>
<CreateProduct.AdditionalInfo>
<CreateProduct.AdditionalInfo.Title />
<CreateProduct.AdditionalInfo.Subtitle />
<CreateProduct.AdditionalInfo.Address1Field />
<CreateProduct.AdditionalInfo.Address2Field />
</CreateProduct.AdditionalInfo>
<CreateProduct.Actions>
<CreateProduct.Actions.SubmitButton>Create Product</CreateProduct.Actions.SubmitButton>
</CreateProduct.Actions>
</CreateProduct>
);
};
Built with β€οΈ using React, TypeScript, and modern web standards.