@vendure/dashboard 3.5.0-minor-202510071456 → 3.5.0-minor-202510161257

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.
Files changed (201) hide show
  1. package/dist/plugin/dashboard.plugin.js +1 -1
  2. package/dist/vite/utils/ast-utils.spec.js +3 -3
  3. package/dist/vite/vite-plugin-hmr.d.ts +8 -0
  4. package/dist/vite/vite-plugin-hmr.js +34 -0
  5. package/dist/vite/vite-plugin-theme.js +6 -6
  6. package/dist/vite/vite-plugin-transform-index.js +6 -1
  7. package/dist/vite/vite-plugin-vendure-dashboard.d.ts +31 -4
  8. package/dist/vite/vite-plugin-vendure-dashboard.js +89 -34
  9. package/package.json +17 -5
  10. package/src/app/app-providers.tsx +4 -1
  11. package/src/app/common/map-faceted-filter-fields.ts +21 -0
  12. package/src/app/main.tsx +3 -1
  13. package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +2 -2
  14. package/src/app/routes/_authenticated/_administrators/administrators.tsx +13 -3
  15. package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +6 -13
  16. package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +1 -1
  17. package/src/app/routes/_authenticated/_assets/assets.tsx +17 -1
  18. package/src/app/routes/_authenticated/_collections/collections.graphql.ts +1 -0
  19. package/src/app/routes/_authenticated/_collections/collections.tsx +5 -0
  20. package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +0 -1
  21. package/src/app/routes/_authenticated/_customers/customers.tsx +9 -5
  22. package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +0 -6
  23. package/src/app/routes/_authenticated/_facets/components/facet-value-bulk-actions.tsx +16 -0
  24. package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +43 -12
  25. package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +14 -5
  26. package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +117 -92
  27. package/src/app/routes/_authenticated/_orders/components/order-detail-shared.tsx +1 -1
  28. package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +2 -1
  29. package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +26 -27
  30. package/src/app/routes/_authenticated/_orders/components/order-table.tsx +5 -3
  31. package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +6 -9
  32. package/src/app/routes/_authenticated/_orders/orders.graphql.ts +17 -1
  33. package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +48 -281
  34. package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +59 -40
  35. package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +73 -0
  36. package/src/app/routes/_authenticated/_orders/utils/use-modify-order.ts +312 -0
  37. package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +2 -2
  38. package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +4 -0
  39. package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +0 -6
  40. package/src/app/routes/_authenticated/_products/products.tsx +6 -2
  41. package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +4 -8
  42. package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +0 -10
  43. package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +2 -2
  44. package/src/app/routes/_authenticated/_promotions/promotions.tsx +12 -0
  45. package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +6 -2
  46. package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +2 -2
  47. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +2 -2
  48. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +4 -0
  49. package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +4 -10
  50. package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +2 -2
  51. package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +2 -2
  52. package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +9 -0
  53. package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +1 -0
  54. package/src/app/routes/_authenticated/_zones/zones.graphql.ts +2 -2
  55. package/src/app/routes/login.tsx +2 -2
  56. package/src/i18n/locales/ar.po +420 -289
  57. package/src/i18n/locales/cs.po +420 -289
  58. package/src/i18n/locales/de.po +420 -289
  59. package/src/i18n/locales/en.po +420 -289
  60. package/src/i18n/locales/es.po +420 -289
  61. package/src/i18n/locales/fa.po +420 -289
  62. package/src/i18n/locales/fr.po +468 -337
  63. package/src/i18n/locales/he.po +420 -289
  64. package/src/i18n/locales/hr.po +420 -289
  65. package/src/i18n/locales/it.po +420 -289
  66. package/src/i18n/locales/ja.po +420 -289
  67. package/src/i18n/locales/nb.po +420 -289
  68. package/src/i18n/locales/ne.po +420 -289
  69. package/src/i18n/locales/pl.po +420 -289
  70. package/src/i18n/locales/pt_BR.po +420 -289
  71. package/src/i18n/locales/pt_PT.po +420 -289
  72. package/src/i18n/locales/ru.po +420 -289
  73. package/src/i18n/locales/sv.po +420 -289
  74. package/src/i18n/locales/tr.po +420 -289
  75. package/src/i18n/locales/uk.po +420 -289
  76. package/src/i18n/locales/zh_Hans.po +420 -289
  77. package/src/i18n/locales/zh_Hant.po +420 -289
  78. package/src/lib/components/data-input/affixed-input.stories.tsx +93 -0
  79. package/src/lib/components/data-input/affixed-input.tsx +5 -2
  80. package/src/lib/components/data-input/boolean-input.stories.tsx +102 -0
  81. package/src/lib/components/data-input/checkbox-input.stories.tsx +61 -0
  82. package/src/lib/components/data-input/datetime-input.stories.tsx +62 -0
  83. package/src/lib/components/data-input/datetime-input.tsx +27 -13
  84. package/src/lib/components/data-input/default-relation-input.tsx +18 -12
  85. package/src/lib/components/data-input/money-input.stories.tsx +88 -0
  86. package/src/lib/components/data-input/number-input.stories.tsx +103 -0
  87. package/src/lib/components/data-input/number-input.tsx +10 -4
  88. package/src/lib/components/data-input/password-input.stories.tsx +65 -0
  89. package/src/lib/components/data-input/rich-text-input.stories.tsx +92 -0
  90. package/src/lib/components/data-input/slug-input.stories.tsx +232 -0
  91. package/src/lib/components/data-input/slug-input.tsx +9 -10
  92. package/src/lib/components/data-input/text-input.stories.tsx +52 -0
  93. package/src/lib/components/data-input/textarea-input.stories.tsx +55 -0
  94. package/src/lib/components/data-table/add-filter-menu.tsx +6 -1
  95. package/src/lib/components/data-table/column-header-wrapper.tsx +106 -0
  96. package/src/lib/components/data-table/data-table-bulk-action-item.tsx +11 -9
  97. package/src/lib/components/data-table/data-table-bulk-actions.tsx +4 -4
  98. package/src/lib/components/data-table/data-table-column-header.tsx +17 -14
  99. package/src/lib/components/data-table/data-table-faceted-filter.tsx +33 -11
  100. package/src/lib/components/data-table/data-table-filter-badge-editable.tsx +35 -0
  101. package/src/lib/components/data-table/data-table-filter-badge.tsx +23 -16
  102. package/src/lib/components/data-table/data-table-filter-dialog.tsx +28 -8
  103. package/src/lib/components/data-table/data-table-pagination.tsx +23 -7
  104. package/src/lib/components/data-table/data-table.stories.tsx +249 -0
  105. package/src/lib/components/data-table/data-table.tsx +37 -9
  106. package/src/lib/components/data-table/filters/data-table-datetime-filter.tsx +79 -34
  107. package/src/lib/components/data-table/use-generated-columns.tsx +55 -27
  108. package/src/lib/components/layout/nav-user.tsx +19 -13
  109. package/src/lib/components/login/login-form.tsx +39 -123
  110. package/src/lib/components/shared/alerts.tsx +29 -17
  111. package/src/lib/components/shared/asset/asset-bulk-actions.tsx +3 -3
  112. package/src/lib/components/shared/asset/asset-gallery.stories.tsx +76 -0
  113. package/src/lib/components/shared/asset/asset-gallery.tsx +147 -113
  114. package/src/lib/components/shared/asset/asset-picker-dialog.stories.tsx +58 -0
  115. package/src/lib/components/shared/customer-group-selector.tsx +5 -2
  116. package/src/lib/components/shared/detail-page-button.stories.tsx +52 -0
  117. package/src/lib/components/shared/facet-value-selector.stories.tsx +48 -0
  118. package/src/lib/components/shared/facet-value-selector.tsx +130 -34
  119. package/src/lib/components/shared/paginated-list-data-table.stories.tsx +212 -0
  120. package/src/lib/components/shared/paginated-list-data-table.tsx +12 -12
  121. package/src/lib/components/shared/permission-guard.stories.tsx +46 -0
  122. package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +2 -0
  123. package/src/lib/components/shared/rich-text-editor/responsive-toolbar.tsx +8 -4
  124. package/src/lib/components/shared/rich-text-editor/rich-text-editor.tsx +1 -0
  125. package/src/lib/components/shared/table-cell/order-table-cell-components.tsx +40 -0
  126. package/src/lib/components/shared/vendure-image.stories.tsx +167 -0
  127. package/src/lib/components/shared/vendure-image.tsx +6 -7
  128. package/src/lib/components/ui/accordion.stories.tsx +33 -0
  129. package/src/lib/components/ui/alert-dialog.stories.tsx +48 -0
  130. package/src/lib/components/ui/alert.stories.tsx +35 -0
  131. package/src/lib/components/ui/aspect-ratio.stories.tsx +28 -0
  132. package/src/lib/components/ui/badge.stories.tsx +28 -0
  133. package/src/lib/components/ui/breadcrumb.stories.tsx +41 -0
  134. package/src/lib/components/ui/button.stories.tsx +38 -0
  135. package/src/lib/components/ui/calendar.stories.tsx +22 -0
  136. package/src/lib/components/ui/card.stories.tsx +28 -0
  137. package/src/lib/components/ui/carousel.stories.tsx +34 -0
  138. package/src/lib/components/ui/checkbox.stories.tsx +31 -0
  139. package/src/lib/components/ui/collapsible.stories.tsx +39 -0
  140. package/src/lib/components/ui/command.stories.tsx +44 -0
  141. package/src/lib/components/ui/context-menu.stories.tsx +38 -0
  142. package/src/lib/components/ui/dialog.stories.tsx +52 -0
  143. package/src/lib/components/ui/drawer.stories.tsx +50 -0
  144. package/src/lib/components/ui/dropdown-menu.stories.tsx +41 -0
  145. package/src/lib/components/ui/hover-card.stories.tsx +38 -0
  146. package/src/lib/components/ui/input-group.tsx +148 -0
  147. package/src/lib/components/ui/input-otp.stories.tsx +30 -0
  148. package/src/lib/components/ui/input.stories.tsx +38 -0
  149. package/src/lib/components/ui/label.stories.tsx +24 -0
  150. package/src/lib/components/ui/menubar.stories.tsx +53 -0
  151. package/src/lib/components/ui/navigation-menu.stories.tsx +54 -0
  152. package/src/lib/components/ui/pagination.stories.tsx +51 -0
  153. package/src/lib/components/ui/password-input.stories.tsx +32 -0
  154. package/src/lib/components/ui/password-input.tsx +33 -0
  155. package/src/lib/components/ui/popover.stories.tsx +33 -0
  156. package/src/lib/components/ui/progress.stories.tsx +27 -0
  157. package/src/lib/components/ui/radio-group.stories.tsx +34 -0
  158. package/src/lib/components/ui/resizable.stories.tsx +32 -0
  159. package/src/lib/components/ui/scroll-area.stories.tsx +31 -0
  160. package/src/lib/components/ui/select.stories.tsx +36 -0
  161. package/src/lib/components/ui/separator.stories.tsx +35 -0
  162. package/src/lib/components/ui/sheet.stories.tsx +50 -0
  163. package/src/lib/components/ui/sidebar-context.ts +16 -0
  164. package/src/lib/components/ui/sidebar.tsx +2 -13
  165. package/src/lib/components/ui/skeleton.stories.tsx +26 -0
  166. package/src/lib/components/ui/slider.stories.tsx +37 -0
  167. package/src/lib/components/ui/switch.stories.tsx +31 -0
  168. package/src/lib/components/ui/table.stories.tsx +52 -0
  169. package/src/lib/components/ui/tabs.stories.tsx +29 -0
  170. package/src/lib/components/ui/textarea.stories.tsx +32 -0
  171. package/src/lib/components/ui/toggle-group.stories.tsx +31 -0
  172. package/src/lib/components/ui/toggle.stories.tsx +39 -0
  173. package/src/lib/components/ui/tooltip.stories.tsx +30 -0
  174. package/src/lib/components/ui/tooltip.tsx +2 -2
  175. package/src/lib/framework/alert/alert-extensions.tsx +0 -11
  176. package/src/lib/framework/alert/alert-item.tsx +14 -19
  177. package/src/lib/framework/alert/alerts-indicator.tsx +14 -15
  178. package/src/lib/framework/alert/search-index-buffer-alert/search-index-buffer-alert.ts +41 -0
  179. package/src/lib/framework/component-registry/component-registry.tsx +3 -14
  180. package/src/lib/framework/dashboard-widget/base-widget.tsx +18 -9
  181. package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +12 -11
  182. package/src/lib/framework/defaults.ts +9 -13
  183. package/src/lib/framework/extension-api/input-component-extensions.tsx +6 -1
  184. package/src/lib/framework/extension-api/logic/alerts.ts +3 -2
  185. package/src/lib/framework/extension-api/types/alerts.ts +12 -6
  186. package/src/lib/framework/extension-api/types/data-table.ts +5 -2
  187. package/src/lib/framework/extension-api/types/login.ts +0 -21
  188. package/src/lib/framework/layout-engine/custom-form-page.stories.tsx +344 -0
  189. package/src/lib/framework/layout-engine/page-layout.tsx +11 -9
  190. package/src/lib/framework/layout-engine/page.stories.tsx +275 -0
  191. package/src/lib/framework/nav-menu/nav-menu-extensions.ts +32 -19
  192. package/src/lib/framework/page/detail-page.stories.tsx +151 -0
  193. package/src/lib/framework/page/list-page.stories.tsx +217 -0
  194. package/src/lib/framework/page/list-page.tsx +8 -1
  195. package/src/lib/graphql/api.ts +18 -1
  196. package/src/lib/graphql/graphql-env.d.ts +1 -1
  197. package/src/lib/hooks/use-alerts.ts +84 -0
  198. package/src/lib/hooks/use-floating-bulk-actions.ts +2 -3
  199. package/src/lib/index.ts +12 -5
  200. package/src/lib/providers/alerts-provider.tsx +60 -0
  201. package/src/lib/providers/theme-provider.tsx +6 -3
@@ -4,6 +4,8 @@ import { Badge } from '@/vdb/components/ui/badge.js';
4
4
  import { Button } from '@/vdb/components/ui/button.js';
5
5
  import { useDynamicTranslations } from '@/vdb/hooks/use-dynamic-translations.js';
6
6
  import { Link } from '@tanstack/react-router';
7
+ import { ChevronDown, ChevronUp } from 'lucide-react';
8
+ import { useMemo, useState } from 'react';
7
9
 
8
10
  type CustomerCellData = {
9
11
  customer: {
@@ -38,3 +40,41 @@ export const OrderMoneyCell: DataTableCellComponent<{ currencyCode: string }> =
38
40
  const currencyCode = row.original.currencyCode;
39
41
  return <Money value={value} currency={currencyCode} />;
40
42
  };
43
+
44
+ export const RichTextDescriptionCell: DataTableCellComponent<{ description: string }> = ({ cell }) => {
45
+ const [isExpanded, setIsExpanded] = useState(false);
46
+ const value = cell.getValue();
47
+
48
+ // Strip HTML tags and decode HTML entities
49
+ const textContent = useMemo(() => {
50
+ const stripped = value?.replace(/<[^>]*>/g, '') || '';
51
+ const textArea = document.createElement('textarea');
52
+ textArea.innerHTML = stripped;
53
+ return textArea.value;
54
+ }, [value]);
55
+
56
+ const shortLength = 100;
57
+ const maxLength = 500;
58
+ const isTooLong = textContent.length > shortLength;
59
+
60
+ const displayText = isExpanded ? textContent.slice(0, maxLength) : textContent.slice(0, shortLength);
61
+
62
+ return (
63
+ <div>
64
+ <div>
65
+ {displayText}
66
+ {!isExpanded && isTooLong && '...'}
67
+ </div>
68
+ {!isExpanded && isTooLong && (
69
+ <Button onClick={() => setIsExpanded(true)} variant="ghost" size="xs">
70
+ <ChevronDown />
71
+ </Button>
72
+ )}
73
+ {isExpanded && (
74
+ <Button onClick={() => setIsExpanded(false)} variant="ghost" size="xs">
75
+ <ChevronUp />
76
+ </Button>
77
+ )}
78
+ </div>
79
+ );
80
+ };
@@ -0,0 +1,167 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { withDescription } from '../../../../.storybook/with-description.js';
3
+ import type { AssetLike } from './vendure-image.js';
4
+ import { VendureImage } from './vendure-image.js';
5
+
6
+ // Mock asset data for demonstrations
7
+ const mockAsset: AssetLike = {
8
+ id: '1',
9
+ preview: 'https://demo.vendure.io/assets/preview/ed/chuttersnap-584518-unsplash__preview.jpg',
10
+ name: 'Sample Image',
11
+ };
12
+
13
+ const mockAssetWithFocalPoint: AssetLike = {
14
+ id: '2',
15
+ preview: 'https://demo.vendure.io/assets/preview/ed/chuttersnap-584518-unsplash__preview.jpg',
16
+ name: 'Image with Focal Point',
17
+ focalPoint: { x: 0.75, y: 0.25 },
18
+ };
19
+
20
+ const meta = {
21
+ title: 'Components/VendureImage',
22
+ component: VendureImage,
23
+ ...withDescription(import.meta.url, './vendure-image.js'),
24
+ parameters: {
25
+ layout: 'centered',
26
+ },
27
+ tags: ['autodocs'],
28
+ argTypes: {
29
+ preset: {
30
+ control: 'select',
31
+ options: ['tiny', 'thumb', 'small', 'medium', 'large', 'full', null],
32
+ description: 'The preset to use for the image',
33
+ },
34
+ mode: {
35
+ control: 'select',
36
+ options: ['crop', 'resize', null],
37
+ description: 'The crop/resize mode to use',
38
+ },
39
+ width: {
40
+ control: 'number',
41
+ description: 'Custom width in pixels',
42
+ },
43
+ height: {
44
+ control: 'number',
45
+ description: 'Custom height in pixels',
46
+ },
47
+ format: {
48
+ control: 'select',
49
+ options: ['jpg', 'jpeg', 'png', 'webp', 'avif', null],
50
+ description: 'The image format',
51
+ },
52
+ quality: {
53
+ control: { type: 'range', min: 1, max: 100, step: 1 },
54
+ description: 'Image quality (1-100)',
55
+ },
56
+ useFocalPoint: {
57
+ control: 'boolean',
58
+ description: 'Whether to use the focal point in crop mode',
59
+ },
60
+ },
61
+ } satisfies Meta<typeof VendureImage>;
62
+
63
+ export default meta;
64
+ type Story = StoryObj<typeof meta>;
65
+
66
+ export const Playground: Story = {
67
+ args: {
68
+ asset: mockAsset,
69
+ preset: 'medium',
70
+ useFocalPoint: true,
71
+ },
72
+ render: args => {
73
+ return <VendureImage {...args} />;
74
+ },
75
+ };
76
+
77
+ export const PresetSizes: Story = {
78
+ render: () => {
79
+ return (
80
+ <div className="space-y-4">
81
+ <div className="space-y-2">
82
+ <div className="text-sm font-medium">Tiny (50x50)</div>
83
+ <VendureImage asset={mockAsset} preset="tiny" />
84
+ </div>
85
+ <div className="space-y-2">
86
+ <div className="text-sm font-medium">Thumb (150x150)</div>
87
+ <VendureImage asset={mockAsset} preset="thumb" />
88
+ </div>
89
+ <div className="space-y-2">
90
+ <div className="text-sm font-medium">Small (300x300)</div>
91
+ <VendureImage asset={mockAsset} preset="small" />
92
+ </div>
93
+ <div className="space-y-2">
94
+ <div className="text-sm font-medium">Medium (500x500)</div>
95
+ <VendureImage asset={mockAsset} preset="medium" />
96
+ </div>
97
+ </div>
98
+ );
99
+ },
100
+ };
101
+
102
+ export const CustomDimensions: Story = {
103
+ render: () => {
104
+ return (
105
+ <div className="space-y-4">
106
+ <div className="space-y-2">
107
+ <div className="text-sm font-medium">200x200 - Crop Mode</div>
108
+ <VendureImage asset={mockAsset} width={200} height={200} mode="crop" />
109
+ </div>
110
+ <div className="space-y-2">
111
+ <div className="text-sm font-medium">300x150 - Crop Mode</div>
112
+ <VendureImage asset={mockAsset} width={300} height={150} mode="crop" />
113
+ </div>
114
+ <div className="space-y-2">
115
+ <div className="text-sm font-medium">200x200 - Resize Mode</div>
116
+ <VendureImage asset={mockAsset} width={200} height={200} mode="resize" />
117
+ </div>
118
+ </div>
119
+ );
120
+ },
121
+ };
122
+
123
+ export const Formats: Story = {
124
+ render: () => {
125
+ return (
126
+ <div className="space-y-4">
127
+ <div className="space-y-2">
128
+ <div className="text-sm font-medium">WebP Format</div>
129
+ <VendureImage asset={mockAsset} preset="thumb" format="webp" />
130
+ </div>
131
+ <div className="space-y-2">
132
+ <div className="text-sm font-medium">AVIF Format</div>
133
+ <VendureImage asset={mockAsset} preset="thumb" format="avif" />
134
+ </div>
135
+ <div className="space-y-2">
136
+ <div className="text-sm font-medium">JPEG Format with Quality 50</div>
137
+ <VendureImage asset={mockAsset} preset="thumb" format="jpeg" quality={50} />
138
+ </div>
139
+ </div>
140
+ );
141
+ },
142
+ };
143
+
144
+ export const Fallbacks: Story = {
145
+ render: () => {
146
+ return (
147
+ <div className="space-y-4">
148
+ <div className="space-y-2">
149
+ <div className="text-sm font-medium">No Asset - Default Placeholder</div>
150
+ <VendureImage asset={null} preset="thumb" />
151
+ </div>
152
+ <div className="space-y-2">
153
+ <div className="text-sm font-medium">No Asset - Custom Fallback</div>
154
+ <VendureImage
155
+ asset={null}
156
+ preset="thumb"
157
+ fallback={
158
+ <div className="w-[150px] h-[150px] bg-gray-200 flex items-center justify-center rounded-sm">
159
+ <span className="text-gray-500">Custom Fallback</span>
160
+ </div>
161
+ }
162
+ />
163
+ </div>
164
+ </div>
165
+ );
166
+ },
167
+ };
@@ -99,9 +99,9 @@ export interface VendureImageProps extends React.ImgHTMLAttributes<HTMLImageElem
99
99
  useFocalPoint?: boolean;
100
100
  /**
101
101
  * @description
102
- * The fallback to show if no asset is provided. If no fallback is provided,
102
+ * The fallback to show if no asset is provided. If no fallback is provided,
103
103
  * a default placeholder will be shown.
104
- */
104
+ */
105
105
  fallback?: React.ReactNode;
106
106
  /**
107
107
  * @description
@@ -113,9 +113,9 @@ export interface VendureImageProps extends React.ImgHTMLAttributes<HTMLImageElem
113
113
  /**
114
114
  * @description
115
115
  * A component for displaying an image from a Vendure asset.
116
- *
116
+ *
117
117
  * Supports the following features:
118
- *
118
+ *
119
119
  * * Presets
120
120
  * * Cropping
121
121
  * * Resizing
@@ -123,7 +123,7 @@ export interface VendureImageProps extends React.ImgHTMLAttributes<HTMLImageElem
123
123
  * * Quality
124
124
  * * Focal point
125
125
  * * Fallback
126
- *
126
+ *
127
127
  * @example
128
128
  * ```tsx
129
129
  * <VendureImage
@@ -154,14 +154,13 @@ export function VendureImage({
154
154
  ref,
155
155
  ...imgProps
156
156
  }: VendureImageProps) {
157
- if (!asset) {
157
+ if (!asset || !asset.preview) {
158
158
  return fallback ? (
159
159
  <>{fallback}</>
160
160
  ) : (
161
161
  <PlaceholderImage preset={preset} width={width} height={height} className={className} />
162
162
  );
163
163
  }
164
-
165
164
  // Build the URL with query parameters
166
165
  const url = new URL(asset.preview);
167
166
 
@@ -0,0 +1,33 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './accordion.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Accordion',
6
+ component: Accordion,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof Accordion>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Playground: Story = {
17
+ render: () => (
18
+ <Accordion type="single" collapsible className="w-[400px]">
19
+ <AccordionItem value="item-1">
20
+ <AccordionTrigger>Item 1</AccordionTrigger>
21
+ <AccordionContent>Content for item 1</AccordionContent>
22
+ </AccordionItem>
23
+ <AccordionItem value="item-2">
24
+ <AccordionTrigger>Item 2</AccordionTrigger>
25
+ <AccordionContent>Content for item 2</AccordionContent>
26
+ </AccordionItem>
27
+ <AccordionItem value="item-3">
28
+ <AccordionTrigger>Item 3</AccordionTrigger>
29
+ <AccordionContent>Content for item 3</AccordionContent>
30
+ </AccordionItem>
31
+ </Accordion>
32
+ ),
33
+ };
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from 'react';
3
+ import {
4
+ AlertDialog,
5
+ AlertDialogAction,
6
+ AlertDialogCancel,
7
+ AlertDialogContent,
8
+ AlertDialogDescription,
9
+ AlertDialogFooter,
10
+ AlertDialogHeader,
11
+ AlertDialogTitle,
12
+ AlertDialogTrigger,
13
+ } from './alert-dialog.js';
14
+ import { Button } from './button.js';
15
+
16
+ const meta = {
17
+ title: 'UI/Alert Dialog',
18
+ component: AlertDialog,
19
+ parameters: {
20
+ layout: 'centered',
21
+ },
22
+ tags: ['autodocs'],
23
+ } satisfies Meta<typeof AlertDialog>;
24
+
25
+ export default meta;
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ export const Playground: Story = {
29
+ render: () => (
30
+ <AlertDialog>
31
+ <AlertDialogTrigger asChild>
32
+ <Button variant="destructive">Delete Item</Button>
33
+ </AlertDialogTrigger>
34
+ <AlertDialogContent>
35
+ <AlertDialogHeader>
36
+ <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
37
+ <AlertDialogDescription>
38
+ This action cannot be undone. This will permanently delete your item.
39
+ </AlertDialogDescription>
40
+ </AlertDialogHeader>
41
+ <AlertDialogFooter>
42
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
43
+ <AlertDialogAction>Continue</AlertDialogAction>
44
+ </AlertDialogFooter>
45
+ </AlertDialogContent>
46
+ </AlertDialog>
47
+ ),
48
+ };
@@ -0,0 +1,35 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { AlertCircle } from 'lucide-react';
3
+ import { Alert, AlertDescription, AlertTitle } from './alert.js';
4
+
5
+ const meta = {
6
+ title: 'UI/Alert',
7
+ component: Alert,
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ tags: ['autodocs'],
12
+ argTypes: {
13
+ variant: {
14
+ control: 'select',
15
+ options: ['default', 'destructive'],
16
+ description: 'Alert variant',
17
+ },
18
+ },
19
+ } satisfies Meta<typeof Alert>;
20
+
21
+ export default meta;
22
+ type Story = StoryObj<typeof meta>;
23
+
24
+ export const Playground: Story = {
25
+ render: args => (
26
+ <Alert {...args} className="w-[400px]">
27
+ <AlertCircle className="h-4 w-4" />
28
+ <AlertTitle>Heads up!</AlertTitle>
29
+ <AlertDescription>You can add components to your app using the cli.</AlertDescription>
30
+ </Alert>
31
+ ),
32
+ args: {
33
+ variant: 'default',
34
+ },
35
+ };
@@ -0,0 +1,28 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { AspectRatio } from './aspect-ratio.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Aspect Ratio',
6
+ component: AspectRatio,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof AspectRatio>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Playground: Story = {
17
+ render: () => (
18
+ <div className="w-[400px]">
19
+ <AspectRatio ratio={16 / 9}>
20
+ <img
21
+ src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
22
+ alt="Photo"
23
+ className="rounded-md object-cover w-full h-full"
24
+ />
25
+ </AspectRatio>
26
+ </div>
27
+ ),
28
+ };
@@ -0,0 +1,28 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Badge } from './badge.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Badge',
6
+ component: Badge,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ variant: {
13
+ control: 'select',
14
+ options: ['default', 'secondary', 'destructive', 'outline'],
15
+ description: 'Badge variant',
16
+ },
17
+ },
18
+ } satisfies Meta<typeof Badge>;
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Playground: Story = {
24
+ args: {
25
+ variant: 'default',
26
+ children: 'Badge',
27
+ },
28
+ };
@@ -0,0 +1,41 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import {
3
+ Breadcrumb,
4
+ BreadcrumbItem,
5
+ BreadcrumbLink,
6
+ BreadcrumbList,
7
+ BreadcrumbPage,
8
+ BreadcrumbSeparator,
9
+ } from './breadcrumb.js';
10
+
11
+ const meta = {
12
+ title: 'UI/Breadcrumb',
13
+ component: Breadcrumb,
14
+ parameters: {
15
+ layout: 'centered',
16
+ },
17
+ tags: ['autodocs'],
18
+ } satisfies Meta<typeof Breadcrumb>;
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof meta>;
22
+
23
+ export const Playground: Story = {
24
+ render: () => (
25
+ <Breadcrumb>
26
+ <BreadcrumbList>
27
+ <BreadcrumbItem>
28
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
29
+ </BreadcrumbItem>
30
+ <BreadcrumbSeparator />
31
+ <BreadcrumbItem>
32
+ <BreadcrumbLink href="/products">Products</BreadcrumbLink>
33
+ </BreadcrumbItem>
34
+ <BreadcrumbSeparator />
35
+ <BreadcrumbItem>
36
+ <BreadcrumbPage>Current Page</BreadcrumbPage>
37
+ </BreadcrumbItem>
38
+ </BreadcrumbList>
39
+ </Breadcrumb>
40
+ ),
41
+ };
@@ -0,0 +1,38 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Button } from './button.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Button',
6
+ component: Button,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ variant: {
13
+ control: 'select',
14
+ options: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'],
15
+ description: 'Button variant',
16
+ },
17
+ size: {
18
+ control: 'select',
19
+ options: ['default', 'sm', 'lg', 'icon'],
20
+ description: 'Button size',
21
+ },
22
+ disabled: {
23
+ control: 'boolean',
24
+ description: 'Whether the button is disabled',
25
+ },
26
+ },
27
+ } satisfies Meta<typeof Button>;
28
+
29
+ export default meta;
30
+ type Story = StoryObj<typeof meta>;
31
+
32
+ export const Playground: Story = {
33
+ args: {
34
+ variant: 'default',
35
+ size: 'default',
36
+ children: 'Button',
37
+ },
38
+ };
@@ -0,0 +1,22 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from 'react';
3
+ import { Calendar } from './calendar.js';
4
+
5
+ const meta = {
6
+ title: 'UI/Calendar',
7
+ component: Calendar,
8
+ parameters: {
9
+ layout: 'centered',
10
+ },
11
+ tags: ['autodocs'],
12
+ } satisfies Meta<typeof Calendar>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Playground: Story = {
18
+ render: () => {
19
+ const [date, setDate] = useState<Date | undefined>(new Date());
20
+ return <Calendar mode="single" selected={date} onSelect={setDate} className="rounded-md border" />;
21
+ },
22
+ };
@@ -0,0 +1,28 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './card.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Card',
6
+ component: Card,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof Card>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Playground: Story = {
17
+ render: () => (
18
+ <Card className="w-[350px]">
19
+ <CardHeader>
20
+ <CardTitle>Card Title</CardTitle>
21
+ <CardDescription>Card description goes here</CardDescription>
22
+ </CardHeader>
23
+ <CardContent>
24
+ <p>Card content goes here</p>
25
+ </CardContent>
26
+ </Card>
27
+ ),
28
+ };
@@ -0,0 +1,34 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from './carousel.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Carousel',
6
+ component: Carousel,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ } satisfies Meta<typeof Carousel>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Playground: Story = {
17
+ render: () => (
18
+ <Carousel className="w-full max-w-xs">
19
+ <CarouselContent>
20
+ {Array.from({ length: 5 }).map((_, index) => (
21
+ <CarouselItem key={index}>
22
+ <div className="p-1">
23
+ <div className="flex aspect-square items-center justify-center p-6 border rounded-lg">
24
+ <span className="text-4xl font-semibold">{index + 1}</span>
25
+ </div>
26
+ </div>
27
+ </CarouselItem>
28
+ ))}
29
+ </CarouselContent>
30
+ <CarouselPrevious />
31
+ <CarouselNext />
32
+ </Carousel>
33
+ ),
34
+ };
@@ -0,0 +1,31 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Checkbox } from './checkbox.js';
3
+
4
+ const meta = {
5
+ title: 'UI/Checkbox',
6
+ component: Checkbox,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ disabled: {
13
+ control: 'boolean',
14
+ description: 'Whether the checkbox is disabled',
15
+ },
16
+ checked: {
17
+ control: 'boolean',
18
+ description: 'Whether the checkbox is checked',
19
+ },
20
+ },
21
+ } satisfies Meta<typeof Checkbox>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ export const Playground: Story = {
27
+ args: {
28
+ checked: false,
29
+ disabled: false,
30
+ },
31
+ };