@vendure/dashboard 3.4.2-master-202509090229 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +4 -4
- package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +4 -4
- package/src/app/routes/_authenticated/_facets/facets.tsx +5 -8
- package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_products/products_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +4 -4
- package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +3 -3
- package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +4 -3
- package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +3 -3
- package/src/lib/components/data-input/affixed-input.tsx +18 -0
- package/src/lib/components/data-input/boolean-input.tsx +7 -0
- package/src/lib/components/data-input/checkbox-input.tsx +7 -0
- package/src/lib/components/data-input/datetime-input.tsx +7 -0
- package/src/lib/components/data-input/money-input.tsx +8 -0
- package/src/lib/components/data-input/number-input.tsx +7 -0
- package/src/lib/components/data-input/password-input.tsx +7 -0
- package/src/lib/components/data-input/rich-text-input.tsx +7 -0
- package/src/lib/components/data-input/text-input.tsx +7 -0
- package/src/lib/components/data-input/textarea-input.tsx +7 -0
- package/src/lib/components/data-table/data-table-view-options.tsx +29 -26
- package/src/lib/components/data-table/data-table.tsx +20 -0
- package/src/lib/components/data-table/types.ts +39 -0
- package/src/lib/components/layout/channel-switcher.tsx +1 -3
- package/src/lib/components/shared/asset/asset-gallery.tsx +58 -0
- package/src/lib/components/shared/asset/asset-picker-dialog.tsx +39 -0
- package/src/lib/components/shared/detail-page-button.tsx +8 -22
- package/src/lib/components/shared/facet-value-chip.tsx +7 -0
- package/src/lib/components/shared/facet-value-selector.tsx +55 -0
- package/src/lib/components/shared/form-field-wrapper.tsx +51 -0
- package/src/lib/components/shared/paginated-list-data-table.tsx +128 -16
- package/src/lib/components/shared/permission-guard.tsx +30 -0
- package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +1 -1
- package/src/lib/components/shared/translatable-form-field.tsx +52 -0
- package/src/lib/components/shared/vendure-image.tsx +114 -2
- package/src/lib/framework/extension-api/define-dashboard-extension.ts +25 -3
- package/src/lib/framework/extension-api/extension-api-types.ts +12 -3
- package/src/lib/framework/extension-api/types/alerts.ts +2 -3
- package/src/lib/framework/extension-api/types/data-table.ts +2 -2
- package/src/lib/framework/extension-api/types/detail-forms.ts +2 -2
- package/src/lib/framework/extension-api/types/form-components.ts +2 -2
- package/src/lib/framework/extension-api/types/layout.ts +24 -13
- package/src/lib/framework/extension-api/types/login.ts +6 -5
- package/src/lib/framework/extension-api/types/navigation.ts +3 -3
- package/src/lib/framework/extension-api/types/widgets.ts +7 -3
- package/src/lib/framework/form-engine/form-engine-types.ts +13 -7
- package/src/lib/framework/form-engine/use-generated-form.tsx +44 -0
- package/src/lib/framework/layout-engine/page-layout.tsx +94 -31
- package/src/lib/framework/page/detail-page.tsx +3 -5
- package/src/lib/framework/page/list-page.tsx +87 -5
- package/src/lib/framework/page/use-detail-page.ts +4 -5
- package/src/lib/graphql/api.ts +2 -2
- package/src/lib/graphql/graphql-env.d.ts +7 -16
- package/src/lib/hooks/use-auth.tsx +1 -3
- package/src/lib/hooks/use-channel.ts +4 -2
- package/src/lib/hooks/use-page-block.tsx +9 -0
- package/src/lib/hooks/use-permissions.ts +6 -2
- package/src/lib/index.ts +2 -0
- package/src/lib/providers/auth.tsx +34 -2
- package/src/lib/providers/channel-provider.tsx +22 -1
- package/src/lib/components/shared/table-cell/table-cell-types.ts +0 -33
|
@@ -2,6 +2,13 @@ import { Checkbox } from '../ui/checkbox.js';
|
|
|
2
2
|
import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
|
|
3
3
|
import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* Displays a boolean value as a checkbox.
|
|
8
|
+
*
|
|
9
|
+
* @docsCategory form-components
|
|
10
|
+
* @docsPage CheckboxInput
|
|
11
|
+
*/
|
|
5
12
|
export function CheckboxInput({ value, onChange, fieldDef }: Readonly<DashboardFormComponentProps>) {
|
|
6
13
|
const readOnly = isReadonlyField(fieldDef);
|
|
7
14
|
return <Checkbox checked={value} onCheckedChange={onChange} disabled={readOnly} />;
|
|
@@ -12,6 +12,13 @@ import { cn } from '@/vdb/lib/utils.js';
|
|
|
12
12
|
import { CalendarClock } from 'lucide-react';
|
|
13
13
|
import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @description
|
|
17
|
+
* A component for selecting a date and time.
|
|
18
|
+
*
|
|
19
|
+
* @docsCategory form-components
|
|
20
|
+
* @docsPage DateTimeInput
|
|
21
|
+
*/
|
|
15
22
|
export function DateTimeInput({ value, onChange, fieldDef }: Readonly<DashboardFormComponentProps>) {
|
|
16
23
|
const readOnly = isReadonlyField(fieldDef);
|
|
17
24
|
const date = value && value instanceof Date ? value.toISOString() : (value ?? '');
|
|
@@ -11,6 +11,14 @@ export interface MoneyInputProps extends DashboardFormComponentProps {
|
|
|
11
11
|
currency?: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @description
|
|
16
|
+
* A component for displaying a money value. The `currency` can be specified, but otherwise
|
|
17
|
+
* will be taken from the active channel's default currency.
|
|
18
|
+
*
|
|
19
|
+
* @docsCategory form-components
|
|
20
|
+
* @docsPage MoneyInput
|
|
21
|
+
*/
|
|
14
22
|
export function MoneyInput(props: Readonly<MoneyInputProps>) {
|
|
15
23
|
const { value, onChange, currency, ...rest } = props;
|
|
16
24
|
const { activeChannel } = useChannel();
|
|
@@ -4,6 +4,13 @@ import { Input } from '@/vdb/components/ui/input.js';
|
|
|
4
4
|
import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
|
|
5
5
|
import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @description
|
|
9
|
+
* A component for displaying a numeric value.
|
|
10
|
+
*
|
|
11
|
+
* @docsCategory form-components
|
|
12
|
+
* @docsPage NumberInput
|
|
13
|
+
*/
|
|
7
14
|
export function NumberInput({ fieldDef, onChange, ...fieldProps }: Readonly<DashboardFormComponentProps>) {
|
|
8
15
|
const readOnly = fieldProps.disabled || isReadonlyField(fieldDef);
|
|
9
16
|
const isFloat = fieldDef ? fieldDef.type === 'float' : false;
|
|
@@ -2,6 +2,13 @@ import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-en
|
|
|
2
2
|
import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
|
|
3
3
|
import { Input } from '../ui/input.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* A component for displaying a password input.
|
|
8
|
+
*
|
|
9
|
+
* @docsCategory form-components
|
|
10
|
+
* @docsPage PasswordInput
|
|
11
|
+
*/
|
|
5
12
|
export function PasswordInput(props: Readonly<DashboardFormComponentProps>) {
|
|
6
13
|
const readOnly = props.disabled || isReadonlyField(props.fieldDef);
|
|
7
14
|
return (
|
|
@@ -22,6 +22,13 @@ const extensions = [
|
|
|
22
22
|
}),
|
|
23
23
|
];
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @description
|
|
27
|
+
* A component for displaying a rich text editor. Internally uses ProseMirror (rich text editor) under the hood.
|
|
28
|
+
*
|
|
29
|
+
* @docsCategory form-components
|
|
30
|
+
* @docsPage RichTextInput
|
|
31
|
+
*/
|
|
25
32
|
export function RichTextInput({ value, onChange, fieldDef }: Readonly<DashboardFormComponentProps>) {
|
|
26
33
|
const readOnly = isReadonlyField(fieldDef);
|
|
27
34
|
const isInternalUpdate = useRef(false);
|
|
@@ -3,6 +3,13 @@ import { Input } from '@/vdb/components/ui/input.js';
|
|
|
3
3
|
import { DashboardFormComponent } from '@/vdb/framework/form-engine/form-engine-types.js';
|
|
4
4
|
import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* A component for displaying a text input.
|
|
9
|
+
*
|
|
10
|
+
* @docsCategory form-components
|
|
11
|
+
* @docsPage TextInput
|
|
12
|
+
*/
|
|
6
13
|
export const TextInput: DashboardFormComponent = ({ value, onChange, fieldDef }) => {
|
|
7
14
|
const readOnly = isReadonlyField(fieldDef);
|
|
8
15
|
return <Input value={value || ''} onChange={e => onChange(e.target.value)} disabled={readOnly} />;
|
|
@@ -2,6 +2,13 @@ import { Textarea } from '@/vdb/components/ui/textarea.js';
|
|
|
2
2
|
import { DashboardFormComponentProps } from '@/vdb/framework/form-engine/form-engine-types.js';
|
|
3
3
|
import { isReadonlyField } from '@/vdb/framework/form-engine/utils.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* A component for displaying a textarea input.
|
|
8
|
+
*
|
|
9
|
+
* @docsCategory form-components
|
|
10
|
+
* @docsPage TextareaInput
|
|
11
|
+
*/
|
|
5
12
|
export function TextareaInput(props: Readonly<DashboardFormComponentProps>) {
|
|
6
13
|
const readOnly = props.disabled || isReadonlyField(props.fieldDef);
|
|
7
14
|
return (
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
DropdownMenuSeparator,
|
|
17
17
|
DropdownMenuTrigger,
|
|
18
18
|
} from '@/vdb/components/ui/dropdown-menu.js';
|
|
19
|
+
import { ScrollArea } from '@/vdb/components/ui/scroll-area.js';
|
|
19
20
|
import { usePage } from '@/vdb/hooks/use-page.js';
|
|
20
21
|
import { useUserSettings } from '@/vdb/hooks/use-user-settings.js';
|
|
21
22
|
import { Trans } from '@/vdb/lib/trans.js';
|
|
@@ -76,39 +77,41 @@ export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps
|
|
|
76
77
|
|
|
77
78
|
return (
|
|
78
79
|
<div className="flex items-center gap-2">
|
|
79
|
-
<DropdownMenu>
|
|
80
|
+
<DropdownMenu modal={false}>
|
|
80
81
|
<DropdownMenuTrigger asChild>
|
|
81
82
|
<Button variant="ghost" size="sm" className="ml-auto hidden h-8 lg:flex">
|
|
82
83
|
<Settings2 />
|
|
83
84
|
<Trans>Columns</Trans>
|
|
84
85
|
</Button>
|
|
85
86
|
</DropdownMenuTrigger>
|
|
86
|
-
<DropdownMenuContent align="end">
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<SortableContext
|
|
93
|
-
items={columns.map(col => col.id)}
|
|
94
|
-
strategy={verticalListSortingStrategy}
|
|
87
|
+
<DropdownMenuContent align="end" className="overflow-auto">
|
|
88
|
+
<ScrollArea className="max-h-[60vh]" type="always">
|
|
89
|
+
<DndContext
|
|
90
|
+
collisionDetection={closestCenter}
|
|
91
|
+
onDragEnd={handleDragEnd}
|
|
92
|
+
modifiers={[restrictToVerticalAxis]}
|
|
95
93
|
>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
94
|
+
<SortableContext
|
|
95
|
+
items={columns.map(col => col.id)}
|
|
96
|
+
strategy={verticalListSortingStrategy}
|
|
97
|
+
>
|
|
98
|
+
{columns.map(column => (
|
|
99
|
+
<SortableItem key={column.id} id={column.id}>
|
|
100
|
+
<DropdownMenuCheckboxItem
|
|
101
|
+
className="capitalize"
|
|
102
|
+
checked={column.getIsVisible()}
|
|
103
|
+
onCheckedChange={value => column.toggleVisibility(!!value)}
|
|
104
|
+
onSelect={e => e.preventDefault()}
|
|
105
|
+
>
|
|
106
|
+
{column.id}
|
|
107
|
+
</DropdownMenuCheckboxItem>
|
|
108
|
+
</SortableItem>
|
|
109
|
+
))}
|
|
110
|
+
</SortableContext>
|
|
111
|
+
</DndContext>
|
|
112
|
+
<DropdownMenuSeparator />
|
|
113
|
+
<DropdownMenuItem onClick={handleReset}>Reset</DropdownMenuItem>
|
|
114
|
+
</ScrollArea>
|
|
112
115
|
</DropdownMenuContent>
|
|
113
116
|
</DropdownMenu>
|
|
114
117
|
</div>
|
|
@@ -35,6 +35,14 @@ export interface FacetedFilter {
|
|
|
35
35
|
options?: DataTableFacetedFilterOption[];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @description
|
|
40
|
+
* Props for configuring the {@link DataTable}.
|
|
41
|
+
*
|
|
42
|
+
* @docsCategory list-views
|
|
43
|
+
* @docsPage DataTable
|
|
44
|
+
* @since 3.4.0
|
|
45
|
+
*/
|
|
38
46
|
interface DataTableProps<TData> {
|
|
39
47
|
children?: React.ReactNode;
|
|
40
48
|
columns: ColumnDef<TData, any>[];
|
|
@@ -55,6 +63,7 @@ interface DataTableProps<TData> {
|
|
|
55
63
|
disableViewOptions?: boolean;
|
|
56
64
|
bulkActions?: BulkAction[];
|
|
57
65
|
/**
|
|
66
|
+
* @description
|
|
58
67
|
* This property allows full control over _all_ features of TanStack Table
|
|
59
68
|
* when needed.
|
|
60
69
|
*/
|
|
@@ -62,6 +71,17 @@ interface DataTableProps<TData> {
|
|
|
62
71
|
onRefresh?: () => void;
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @description
|
|
76
|
+
* A data table which includes sorting, filtering, pagination, bulk actions, column controls etc.
|
|
77
|
+
*
|
|
78
|
+
* This is the building block of all data tables in the Dashboard.
|
|
79
|
+
*
|
|
80
|
+
* @docsCategory list-views
|
|
81
|
+
* @docsPage DataTable
|
|
82
|
+
* @since 3.4.0
|
|
83
|
+
* @docsWeight 0
|
|
84
|
+
*/
|
|
65
85
|
export function DataTable<TData>({
|
|
66
86
|
children,
|
|
67
87
|
columns,
|
|
@@ -1 +1,40 @@
|
|
|
1
|
+
import { CellContext } from '@tanstack/table-core';
|
|
2
|
+
|
|
1
3
|
export type ColumnDataType = 'String' | 'Int' | 'Float' | 'DateTime' | 'Boolean' | 'ID' | 'Money';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* This type is used to define re-usable components that can render a table cell in a
|
|
8
|
+
* DataTable.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { DataTableCellComponent } from '\@vendure/dashboard';
|
|
13
|
+
*
|
|
14
|
+
* type CustomerCellData = {
|
|
15
|
+
* customer: {
|
|
16
|
+
* id: string;
|
|
17
|
+
* firstName: string;
|
|
18
|
+
* lastName: string;
|
|
19
|
+
* } | null;
|
|
20
|
+
* };
|
|
21
|
+
*
|
|
22
|
+
* export const CustomerCell: DataTableCellComponent<CustomerCellData> = ({ row }) => {
|
|
23
|
+
* const value = row.original.customer;
|
|
24
|
+
* if (!value) {
|
|
25
|
+
* return null;
|
|
26
|
+
* }
|
|
27
|
+
* return (
|
|
28
|
+
* <Button asChild variant="ghost">
|
|
29
|
+
* <Link to={`/customers/${value.id}`}>
|
|
30
|
+
* {value.firstName} {value.lastName}
|
|
31
|
+
* </Link>
|
|
32
|
+
* </Button>
|
|
33
|
+
* );
|
|
34
|
+
* };
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @docsCategory list-views
|
|
38
|
+
* @since 3.4.0
|
|
39
|
+
*/
|
|
40
|
+
export type DataTableCellComponent<T> = <Data extends T>(context: CellContext<Data, any>) => any;
|
|
@@ -54,9 +54,7 @@ export function ChannelSwitcher() {
|
|
|
54
54
|
setContentLanguage,
|
|
55
55
|
} = useUserSettings();
|
|
56
56
|
const [showManageLanguagesDialog, setShowManageLanguagesDialog] = useState(false);
|
|
57
|
-
|
|
58
|
-
// Use the selected channel if available, otherwise fall back to the active channel
|
|
59
|
-
const displayChannel = activeChannel || activeChannel;
|
|
57
|
+
const displayChannel = activeChannel;
|
|
60
58
|
|
|
61
59
|
// Get available languages from server config
|
|
62
60
|
const availableLanguages = serverConfig?.availableLanguages || [];
|
|
@@ -71,6 +71,13 @@ const AssetType = {
|
|
|
71
71
|
|
|
72
72
|
export type Asset = AssetFragment;
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @description
|
|
76
|
+
* Props for the {@link AssetGallery} component.
|
|
77
|
+
*
|
|
78
|
+
* @docsCategory components
|
|
79
|
+
* @docsPage AssetGallery
|
|
80
|
+
*/
|
|
74
81
|
export interface AssetGalleryProps {
|
|
75
82
|
onSelect?: (assets: Asset[]) => void;
|
|
76
83
|
selectable?: boolean;
|
|
@@ -82,16 +89,67 @@ export interface AssetGalleryProps {
|
|
|
82
89
|
* If set to 'manual', multiple selection will occur only if the user holds down the control/cmd key.
|
|
83
90
|
*/
|
|
84
91
|
multiSelect?: 'auto' | 'manual';
|
|
92
|
+
/**
|
|
93
|
+
* @description
|
|
94
|
+
* The initial assets that should be selected.
|
|
95
|
+
*/
|
|
85
96
|
initialSelectedAssets?: Asset[];
|
|
97
|
+
/**
|
|
98
|
+
* @description
|
|
99
|
+
* The number of assets to display per page.
|
|
100
|
+
*/
|
|
86
101
|
pageSize?: number;
|
|
102
|
+
/**
|
|
103
|
+
* @description
|
|
104
|
+
* Whether the gallery should have a fixed height.
|
|
105
|
+
*/
|
|
87
106
|
fixedHeight?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* @description
|
|
109
|
+
* Whether the gallery should show a header.
|
|
110
|
+
*/
|
|
88
111
|
showHeader?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* @description
|
|
114
|
+
* The class name to apply to the gallery.
|
|
115
|
+
*/
|
|
89
116
|
className?: string;
|
|
117
|
+
/**
|
|
118
|
+
* @description
|
|
119
|
+
* The function to call when files are dropped.
|
|
120
|
+
*/
|
|
90
121
|
onFilesDropped?: (files: File[]) => void;
|
|
122
|
+
/**
|
|
123
|
+
* @description
|
|
124
|
+
* The bulk actions to display in the gallery.
|
|
125
|
+
*/
|
|
91
126
|
bulkActions?: AssetBulkAction[];
|
|
127
|
+
/**
|
|
128
|
+
* @description
|
|
129
|
+
* Whether the gallery should display bulk actions.
|
|
130
|
+
*/
|
|
92
131
|
displayBulkActions?: boolean;
|
|
93
132
|
}
|
|
94
133
|
|
|
134
|
+
/**
|
|
135
|
+
* @description
|
|
136
|
+
* A component for displaying a gallery of assets.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```tsx
|
|
140
|
+
* <AssetGallery
|
|
141
|
+
onSelect={handleAssetSelect}
|
|
142
|
+
multiSelect="manual"
|
|
143
|
+
initialSelectedAssets={initialSelectedAssets}
|
|
144
|
+
fixedHeight={false}
|
|
145
|
+
displayBulkActions={false}
|
|
146
|
+
/>
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @docsCategory components
|
|
150
|
+
* @docsPage AssetGallery
|
|
151
|
+
* @docsWeight 0
|
|
152
|
+
*/
|
|
95
153
|
export function AssetGallery({
|
|
96
154
|
onSelect,
|
|
97
155
|
selectable = true,
|
|
@@ -9,15 +9,54 @@ import {
|
|
|
9
9
|
import { useState } from 'react';
|
|
10
10
|
import { Asset, AssetGallery } from './asset-gallery.js';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* @description
|
|
14
|
+
* Props for the {@link AssetPickerDialog} component.
|
|
15
|
+
*
|
|
16
|
+
* @docsCategory components
|
|
17
|
+
* @docsPage AssetPickerDialog
|
|
18
|
+
*/
|
|
12
19
|
interface AssetPickerDialogProps {
|
|
20
|
+
/**
|
|
21
|
+
* @description
|
|
22
|
+
* Whether the dialog is open.
|
|
23
|
+
*/
|
|
13
24
|
open: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* @description
|
|
27
|
+
* The function to call when the dialog is closed.
|
|
28
|
+
*/
|
|
14
29
|
onClose: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* @description
|
|
32
|
+
* The function to call when assets are selected.
|
|
33
|
+
*/
|
|
15
34
|
onSelect: (assets: Asset[]) => void;
|
|
35
|
+
/**
|
|
36
|
+
* @description
|
|
37
|
+
* Whether multiple assets can be selected.
|
|
38
|
+
*/
|
|
16
39
|
multiSelect?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* @description
|
|
42
|
+
* The initial assets that should be selected.
|
|
43
|
+
*/
|
|
17
44
|
initialSelectedAssets?: Asset[];
|
|
45
|
+
/**
|
|
46
|
+
* @description
|
|
47
|
+
* The title of the dialog.
|
|
48
|
+
*/
|
|
18
49
|
title?: string;
|
|
19
50
|
}
|
|
20
51
|
|
|
52
|
+
/**
|
|
53
|
+
* @description
|
|
54
|
+
* A dialog which allows the creation and selection of assets.
|
|
55
|
+
*
|
|
56
|
+
* @docsCategory components
|
|
57
|
+
* @docsPage AssetPickerDialog
|
|
58
|
+
* @docsWeight 0
|
|
59
|
+
*/
|
|
21
60
|
export function AssetPickerDialog({
|
|
22
61
|
open,
|
|
23
62
|
onClose,
|
|
@@ -3,46 +3,32 @@ import { ChevronRight } from 'lucide-react';
|
|
|
3
3
|
import { Button } from '../ui/button.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
+
* @description
|
|
6
7
|
* DetailPageButton is a reusable navigation component designed to provide consistent UX
|
|
7
8
|
* across list views when linking to detail pages. It renders as a ghost button with
|
|
8
9
|
* a chevron indicator, making it easy for users to identify clickable links that
|
|
9
10
|
* navigate to detail views.
|
|
10
11
|
*
|
|
11
|
-
* @component
|
|
12
12
|
* @example
|
|
13
|
+
* ```tsx
|
|
13
14
|
* // Basic usage with ID (relative navigation)
|
|
14
15
|
* <DetailPageButton id="123" label="Product Name" />
|
|
16
|
+
*
|
|
15
17
|
*
|
|
16
18
|
* @example
|
|
19
|
+
* ```tsx
|
|
17
20
|
* // Custom href with search params
|
|
18
21
|
* <DetailPageButton
|
|
19
22
|
* href="/products/detail/456"
|
|
20
23
|
* label="Custom Product"
|
|
21
24
|
* search={{ tab: 'variants' }}
|
|
22
25
|
* />
|
|
26
|
+
* ```
|
|
23
27
|
*
|
|
24
|
-
* @example
|
|
25
|
-
* // Disabled state
|
|
26
|
-
* <DetailPageButton
|
|
27
|
-
* id="789"
|
|
28
|
-
* label="Unavailable Item"
|
|
29
|
-
* disabled={true}
|
|
30
|
-
* />
|
|
31
|
-
*
|
|
32
|
-
* @param {Object} props - Component props
|
|
33
|
-
* @param {string|React.ReactNode} props.label - The text or content to display in the button
|
|
34
|
-
* @param {string} [props.id] - The ID for relative navigation (creates href as `./${id}`)
|
|
35
|
-
* @param {string} [props.href] - Custom href for navigation (takes precedence over id)
|
|
36
|
-
* @param {boolean} [props.disabled=false] - Whether the button is disabled (prevents navigation)
|
|
37
|
-
* @param {Record<string, string>} [props.search] - Search parameters to include in the navigation
|
|
38
|
-
*
|
|
39
|
-
* @returns {React.ReactElement} A styled button component that navigates to detail pages
|
|
40
28
|
*
|
|
41
|
-
* @
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* - Preloading is disabled by default for performance optimization
|
|
45
|
-
* - Styled as a ghost button variant for subtle, consistent appearance
|
|
29
|
+
* @docsCategory components
|
|
30
|
+
* @docsPage DetailPageButton
|
|
31
|
+
* @since 3.4.0
|
|
46
32
|
*/
|
|
47
33
|
export function DetailPageButton({
|
|
48
34
|
id,
|
|
@@ -20,6 +20,13 @@ interface FacetValueChipProps {
|
|
|
20
20
|
onRemove?: (id: string) => void;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @description
|
|
25
|
+
* A component for displaying a facet value as a chip.
|
|
26
|
+
*
|
|
27
|
+
* @docsCategory components
|
|
28
|
+
* @since 3.4.0
|
|
29
|
+
*/
|
|
23
30
|
export function FacetValueChip({
|
|
24
31
|
facetValue,
|
|
25
32
|
removable = true,
|
|
@@ -29,10 +29,51 @@ export interface Facet {
|
|
|
29
29
|
code: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @description
|
|
34
|
+
* A component for selecting facet values.
|
|
35
|
+
*
|
|
36
|
+
* @docsCategory components
|
|
37
|
+
* @docsPage FacetValueSelector
|
|
38
|
+
* @since 3.4.0
|
|
39
|
+
*/
|
|
32
40
|
interface FacetValueSelectorProps {
|
|
41
|
+
/**
|
|
42
|
+
* @description
|
|
43
|
+
* The function to call when a facet value is selected.
|
|
44
|
+
*
|
|
45
|
+
* The `value` will have the following structure:
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* {
|
|
49
|
+
* id: string;
|
|
50
|
+
* name: string;
|
|
51
|
+
* code: string;
|
|
52
|
+
* facet: {
|
|
53
|
+
* id: string;
|
|
54
|
+
* name: string;
|
|
55
|
+
* code: string;
|
|
56
|
+
* };
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
33
60
|
onValueSelect: (value: FacetValue) => void;
|
|
61
|
+
/**
|
|
62
|
+
* @description
|
|
63
|
+
* Whether the selector is disabled.
|
|
64
|
+
*/
|
|
34
65
|
disabled?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* @description
|
|
68
|
+
* The placeholder text for the selector.
|
|
69
|
+
*/
|
|
35
70
|
placeholder?: string;
|
|
71
|
+
/**
|
|
72
|
+
* @description
|
|
73
|
+
* The number of facet values to display per page.
|
|
74
|
+
*
|
|
75
|
+
* @default 4
|
|
76
|
+
*/
|
|
36
77
|
pageSize?: number;
|
|
37
78
|
}
|
|
38
79
|
|
|
@@ -85,6 +126,20 @@ const getFacetValuesForFacetDocument = graphql(`
|
|
|
85
126
|
}
|
|
86
127
|
`);
|
|
87
128
|
|
|
129
|
+
/**
|
|
130
|
+
* @description
|
|
131
|
+
* A component for selecting facet values.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* <FacetValueSelector onValueSelect={onValueSelectHandler} disabled={disabled} />
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @docsCategory components
|
|
139
|
+
* @docsPage FacetValueSelector
|
|
140
|
+
* @docsWeight 0
|
|
141
|
+
* @since 3.4.0
|
|
142
|
+
*/
|
|
88
143
|
export function FacetValueSelector({
|
|
89
144
|
onValueSelect,
|
|
90
145
|
disabled,
|
|
@@ -3,11 +3,27 @@ import { LocationWrapper } from '@/vdb/framework/layout-engine/location-wrapper.
|
|
|
3
3
|
import { FieldPath, FieldValues } from 'react-hook-form';
|
|
4
4
|
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '../ui/form.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* The props for the FormFieldWrapper component.
|
|
9
|
+
*
|
|
10
|
+
* @docsCategory form-components
|
|
11
|
+
* @docsPage FormFieldWrapper
|
|
12
|
+
* @since 3.4.0
|
|
13
|
+
*/
|
|
6
14
|
export type FormFieldWrapperProps<
|
|
7
15
|
TFieldValues extends FieldValues = FieldValues,
|
|
8
16
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
9
17
|
> = React.ComponentProps<typeof FormField<TFieldValues, TName>> & {
|
|
18
|
+
/**
|
|
19
|
+
* @description
|
|
20
|
+
* The label for the form field.
|
|
21
|
+
*/
|
|
10
22
|
label?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* @description
|
|
25
|
+
* The description for the form field.
|
|
26
|
+
*/
|
|
11
27
|
description?: React.ReactNode;
|
|
12
28
|
/**
|
|
13
29
|
* @description
|
|
@@ -15,11 +31,46 @@ export type FormFieldWrapperProps<
|
|
|
15
31
|
* If false, the form control will not be rendered.
|
|
16
32
|
* This is useful when you want to render the form control in a custom way, e.g. for <Select/> components,
|
|
17
33
|
* where the FormControl needs to nested in the root component.
|
|
34
|
+
*
|
|
18
35
|
* @default true
|
|
19
36
|
*/
|
|
20
37
|
renderFormControl?: boolean;
|
|
21
38
|
};
|
|
22
39
|
|
|
40
|
+
/**
|
|
41
|
+
* @description
|
|
42
|
+
* This is a wrapper that can be used in all forms to wrap the actual form control, and provide a label, description and error message.
|
|
43
|
+
*
|
|
44
|
+
* Use this instead of the default Shadcn FormField (etc.) components, as it also supports
|
|
45
|
+
* overridden form components.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <PageBlock column="main" blockId="main-form">
|
|
50
|
+
* <DetailFormGrid>
|
|
51
|
+
* <FormFieldWrapper
|
|
52
|
+
* control={form.control}
|
|
53
|
+
* name="description"
|
|
54
|
+
* label={<Trans>Description</Trans>}
|
|
55
|
+
* render={({ field }) => <Input {...field} />}
|
|
56
|
+
* />
|
|
57
|
+
* <FormFieldWrapper
|
|
58
|
+
* control={form.control}
|
|
59
|
+
* name="code"
|
|
60
|
+
* label={<Trans>Code</Trans>}
|
|
61
|
+
* render={({ field }) => <Input {...field} />}
|
|
62
|
+
* />
|
|
63
|
+
* </DetailFormGrid>
|
|
64
|
+
* </PageBlock>
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* If you are dealing with translatable fields, use the {@link TranslatableFormFieldWrapper} component instead.
|
|
68
|
+
*
|
|
69
|
+
* @docsCategory form-components
|
|
70
|
+
* @docsPage FormFieldWrapper
|
|
71
|
+
* @docsWeight 0
|
|
72
|
+
* @since 3.4.0
|
|
73
|
+
*/
|
|
23
74
|
export function FormFieldWrapper<
|
|
24
75
|
TFieldValues extends FieldValues = FieldValues,
|
|
25
76
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|