@donotdev/ui 0.0.13 → 0.0.15

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 (163) hide show
  1. package/dist/components/auth/AuthMenu.d.ts.map +1 -1
  2. package/dist/components/auth/AuthMenu.js +19 -20
  3. package/dist/components/common/FeatureCard.d.ts +3 -1
  4. package/dist/components/common/FeatureCard.d.ts.map +1 -1
  5. package/dist/components/common/FeatureCard.js +2 -2
  6. package/dist/components/common/ProgressBar.js +2 -2
  7. package/dist/components/common/TechBento.d.ts +14 -2
  8. package/dist/components/common/TechBento.d.ts.map +1 -1
  9. package/dist/components/common/TechBento.js +8 -9
  10. package/dist/components/cookie-consent/CookieConsent.d.ts.map +1 -1
  11. package/dist/components/cookie-consent/CookieConsent.js +3 -4
  12. package/dist/components/layout/components/DropdownNavigation.d.ts.map +1 -1
  13. package/dist/components/layout/components/DropdownNavigation.js +3 -12
  14. package/dist/components/layout/components/FloatingLanguageSwitcher.js +1 -1
  15. package/dist/components/layout/components/Notifications.d.ts +1 -3
  16. package/dist/components/layout/components/Notifications.d.ts.map +1 -1
  17. package/dist/components/layout/components/Notifications.js +4 -2
  18. package/dist/components/layout/components/header/AppBranding.d.ts.map +1 -1
  19. package/dist/components/layout/components/header/AppBranding.js +2 -1
  20. package/dist/components/layout/components/header/AppIcon.d.ts.map +1 -1
  21. package/dist/components/layout/components/header/AppIcon.js +5 -2
  22. package/dist/components/layout/components/header/CacheSettings.d.ts.map +1 -1
  23. package/dist/components/layout/components/header/CacheSettings.js +3 -1
  24. package/dist/components/layout/components/header/HeaderNavigation.d.ts +6 -0
  25. package/dist/components/layout/components/header/HeaderNavigation.d.ts.map +1 -1
  26. package/dist/components/layout/components/header/HeaderNavigation.js +12 -2
  27. package/dist/components/layout/components/index.d.ts +3 -0
  28. package/dist/components/layout/components/index.d.ts.map +1 -1
  29. package/dist/components/layout/components/index.js +3 -0
  30. package/dist/components/license/LicenseWatermark.d.ts.map +1 -1
  31. package/dist/components/license/LicenseWatermark.js +3 -1
  32. package/dist/crud/components/CrudCardLink.d.ts +17 -0
  33. package/dist/crud/components/CrudCardLink.d.ts.map +1 -0
  34. package/dist/crud/components/CrudCardLink.js +17 -0
  35. package/dist/crud/components/EntityCardList.d.ts +1 -1
  36. package/dist/crud/components/EntityCardList.d.ts.map +1 -1
  37. package/dist/crud/components/EntityCardList.js +38 -90
  38. package/dist/crud/components/EntityDisplayRenderer.d.ts +1 -1
  39. package/dist/crud/components/EntityDisplayRenderer.d.ts.map +1 -1
  40. package/dist/crud/components/EntityDisplayRenderer.js +11 -3
  41. package/dist/crud/components/EntityFormRenderer.d.ts +1 -1
  42. package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
  43. package/dist/crud/components/EntityFormRenderer.js +34 -40
  44. package/dist/crud/components/EntityList.d.ts +1 -1
  45. package/dist/crud/components/EntityList.d.ts.map +1 -1
  46. package/dist/crud/components/EntityList.js +1 -1
  47. package/dist/crud/components/EntityRecommendations.d.ts +29 -0
  48. package/dist/crud/components/EntityRecommendations.d.ts.map +1 -0
  49. package/dist/crud/components/EntityRecommendations.js +32 -0
  50. package/dist/crud/components/index.d.ts +2 -1
  51. package/dist/crud/components/index.d.ts.map +1 -1
  52. package/dist/crud/components/index.js +1 -0
  53. package/dist/dndev.css +1021 -196
  54. package/dist/index.js +4 -4
  55. package/dist/internal/common/RouteErrorFallback.d.ts.map +1 -1
  56. package/dist/internal/devtools/components/AuthDebugButton.js +1 -1
  57. package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -1
  58. package/dist/internal/devtools/components/DesignTab.js +3 -2
  59. package/dist/internal/devtools/components/LayoutReset.d.ts.map +1 -1
  60. package/dist/internal/devtools/components/LayoutReset.js +2 -0
  61. package/dist/internal/devtools/components/StoresTab.d.ts.map +1 -1
  62. package/dist/internal/devtools/components/StoresTab.js +3 -0
  63. package/dist/internal/devtools/utils/envVarDiscovery.d.ts +1 -0
  64. package/dist/internal/devtools/utils/envVarDiscovery.d.ts.map +1 -1
  65. package/dist/internal/devtools/utils/envVarDiscovery.js +5 -0
  66. package/dist/internal/devtools/utils/virtualModuleInspector.d.ts.map +1 -1
  67. package/dist/internal/devtools/utils/virtualModuleInspector.js +27 -21
  68. package/dist/internal/initializers/BaseStoresInitializer.d.ts.map +1 -1
  69. package/dist/internal/initializers/BaseStoresInitializer.js +30 -6
  70. package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
  71. package/dist/internal/layout/components/AutoMetaTags.js +10 -8
  72. package/dist/internal/layout/components/FontPreloadLinks.d.ts +16 -0
  73. package/dist/internal/layout/components/FontPreloadLinks.d.ts.map +1 -0
  74. package/dist/internal/layout/components/FontPreloadLinks.js +32 -0
  75. package/dist/internal/layout/components/PerformanceHints.d.ts +7 -12
  76. package/dist/internal/layout/components/PerformanceHints.d.ts.map +1 -1
  77. package/dist/internal/layout/components/PerformanceHints.js +8 -12
  78. package/dist/internal/layout/components/footer/useLegalLinks.d.ts +6 -5
  79. package/dist/internal/layout/components/footer/useLegalLinks.d.ts.map +1 -1
  80. package/dist/internal/layout/components/footer/useLegalLinks.js +6 -2
  81. package/dist/internal/layout/zones/DnDevFooter.d.ts +6 -0
  82. package/dist/internal/layout/zones/DnDevFooter.d.ts.map +1 -1
  83. package/dist/internal/layout/zones/DnDevFooter.js +10 -4
  84. package/dist/internal/layout/zones/DnDevHeader.d.ts +7 -0
  85. package/dist/internal/layout/zones/DnDevHeader.d.ts.map +1 -1
  86. package/dist/internal/layout/zones/DnDevHeader.js +7 -0
  87. package/dist/internal/layout/zones/DnDevMergedBar.d.ts +7 -0
  88. package/dist/internal/layout/zones/DnDevMergedBar.d.ts.map +1 -1
  89. package/dist/internal/layout/zones/DnDevMergedBar.js +9 -0
  90. package/dist/internal/layout/zones/DnDevSidebar.d.ts +4 -0
  91. package/dist/internal/layout/zones/DnDevSidebar.d.ts.map +1 -1
  92. package/dist/internal/layout/zones/DnDevSidebar.js +13 -1
  93. package/dist/internal/providers/NavigationProvider.d.ts.map +1 -1
  94. package/dist/internal/providers/NavigationProvider.js +3 -5
  95. package/dist/next.d.ts +1 -0
  96. package/dist/next.d.ts.map +1 -1
  97. package/dist/next.js +1 -0
  98. package/dist/providers/ViteAppProviders.d.ts.map +1 -1
  99. package/dist/providers/ViteAppProviders.js +3 -5
  100. package/dist/routing/AuthGuard.d.ts +1 -1
  101. package/dist/routing/AuthGuard.d.ts.map +1 -1
  102. package/dist/routing/AuthGuard.js +3 -1
  103. package/dist/routing/GoTo.d.ts.map +1 -1
  104. package/dist/routing/GoTo.js +3 -1
  105. package/dist/routing/GoToDialog.d.ts.map +1 -1
  106. package/dist/routing/GoToDialog.js +2 -7
  107. package/dist/routing/GoToInput.d.ts +0 -3
  108. package/dist/routing/GoToInput.d.ts.map +1 -1
  109. package/dist/routing/GoToInput.js +8 -7
  110. package/dist/routing/Link.js +1 -1
  111. package/dist/routing/NavigationItem.d.ts +29 -7
  112. package/dist/routing/NavigationItem.d.ts.map +1 -1
  113. package/dist/routing/NavigationItem.js +22 -6
  114. package/dist/routing/hooks/hooks.next.js +1 -1
  115. package/dist/routing/hooks/hooks.vite.js +1 -1
  116. package/dist/routing/hooks/useNavigate.next.d.ts +1 -1
  117. package/dist/routing/hooks/useNavigate.next.d.ts.map +1 -1
  118. package/dist/routing/hooks/useNavigate.next.js +1 -7
  119. package/dist/routing/hooks/useNavigate.vite.d.ts +1 -1
  120. package/dist/routing/hooks/useNavigate.vite.d.ts.map +1 -1
  121. package/dist/routing/hooks/useNavigate.vite.js +1 -7
  122. package/dist/routing/hooks/useRedirectGuard.next.d.ts.map +1 -1
  123. package/dist/routing/hooks/useRedirectGuard.next.js +9 -8
  124. package/dist/routing/hooks/useRedirectGuard.vite.d.ts.map +1 -1
  125. package/dist/routing/hooks/useRedirectGuard.vite.js +9 -8
  126. package/dist/routing/hooks/useSearchParams.next.d.ts +18 -1
  127. package/dist/routing/hooks/useSearchParams.next.d.ts.map +1 -1
  128. package/dist/routing/hooks/useSearchParams.next.js +16 -0
  129. package/dist/routing/hooks/useSearchParams.vite.d.ts +16 -0
  130. package/dist/routing/hooks/useSearchParams.vite.d.ts.map +1 -1
  131. package/dist/routing/hooks/useSearchParams.vite.js +17 -1
  132. package/dist/routing/index.d.ts.map +1 -1
  133. package/dist/routing/index.js +2 -0
  134. package/dist/routing/useNavigation.d.ts +30 -0
  135. package/dist/routing/useNavigation.d.ts.map +1 -1
  136. package/dist/routing/useNavigation.js +40 -3
  137. package/dist/routing/useRouteDiscovery.d.ts +6 -17
  138. package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
  139. package/dist/routing/useRouteDiscovery.js +16 -9
  140. package/dist/styles/index.css +284 -88
  141. package/dist/utils/index.d.ts +1 -0
  142. package/dist/utils/index.d.ts.map +1 -1
  143. package/dist/utils/index.js +1 -0
  144. package/dist/utils/sanitizeSvg.d.ts +13 -0
  145. package/dist/utils/sanitizeSvg.d.ts.map +1 -0
  146. package/dist/utils/sanitizeSvg.js +47 -0
  147. package/dist/utils/useBillingVisibility.d.ts.map +1 -1
  148. package/dist/utils/useBillingVisibility.js +0 -7
  149. package/dist/utils/useCrudSafe.d.ts +0 -2
  150. package/dist/utils/useCrudSafe.d.ts.map +1 -1
  151. package/dist/utils/useFormStoreSafe.d.ts +5 -16
  152. package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
  153. package/dist/utils/useFormStoreSafe.js +6 -37
  154. package/dist/vite-routing/AppRoutes.d.ts +19 -8
  155. package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
  156. package/dist/vite-routing/AppRoutes.js +0 -3
  157. package/dist/vite-routing/RootLayout.d.ts.map +1 -1
  158. package/dist/vite-routing/RootLayout.js +10 -15
  159. package/package.json +16 -12
  160. package/assets/fonts/fonts.css +0 -206
  161. package/dist/routing/Navigate.d.ts +0 -10
  162. package/dist/routing/Navigate.d.ts.map +0 -1
  163. package/dist/routing/Navigate.js +0 -10
@@ -15,10 +15,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
15
15
  */
16
16
  import { useMemo, useCallback } from 'react';
17
17
  import { Heart } from 'lucide-react';
18
- import { Grid, Card, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
19
- import { useTranslation } from '@donotdev/core';
18
+ import { Card, Grid, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
19
+ import { useTranslation, getListCardFieldNames } from '@donotdev/core';
20
20
  import { useNavigate } from '../../routing';
21
- import { translateFieldLabel, useCrudCardList, EntityFilters, useEntityFavorites, matchesFilter, formatValue, useCrudFilters, } from '@donotdev/crud';
21
+ import { useCrudCardList, EntityFilters, useEntityFavorites, matchesFilter, useCrudFilters, } from '@donotdev/crud';
22
+ import { CrudCard } from './CrudCardLink';
22
23
  /**
23
24
  * Entity Card List Component - Card grid view for public/user-facing browsing
24
25
  *
@@ -31,7 +32,7 @@ import { translateFieldLabel, useCrudCardList, EntityFilters, useEntityFavorites
31
32
  * - Auto-routing when handler not provided
32
33
  */
33
34
  export function EntityCardList({ entity, basePath, onClick, cols = [1, 2, 3, 4], staleTime = 1000 * 60 * 30, // 30 minutes default cache
34
- filter, hideFilters = false, }) {
35
+ filter, hideFilters = false, resultLabel, tone, }) {
35
36
  const navigate = useNavigate();
36
37
  const base = basePath ?? `/${entity.collection}`;
37
38
  // useCrudCardList -> handles fetching optimized for cards automatically
@@ -43,11 +44,7 @@ filter, hideFilters = false, }) {
43
44
  });
44
45
  // Favorites toggle from CrudStore (persists across navigation)
45
46
  // Note: EntityFilters now manages its own filters internally via useCrudFilters
46
- const { showFavoritesOnly, setShowFavoritesOnly } = useCrudFilters({
47
- collection: entity.collection,
48
- });
49
- // Get filters for applying to data (EntityFilters manages its own state)
50
- const { filters } = useCrudFilters({
47
+ const { showFavoritesOnly, setShowFavoritesOnly, filters } = useCrudFilters({
51
48
  collection: entity.collection,
52
49
  });
53
50
  // Apply filters from EntityFilters component
@@ -86,96 +83,47 @@ filter, hideFilters = false, }) {
86
83
  navigate(`${base}/${id}`);
87
84
  }
88
85
  }, [base, navigate, onClick]);
89
- // Determine which fields to show in cards
90
- const fieldsToShow = useMemo(() => {
91
- const cardFields = entity.listCardFields ?? entity.listFields;
92
- if (cardFields && cardFields.length > 0)
93
- return cardFields;
94
- return Object.keys(entity.fields).slice(0, 4);
95
- }, [entity.listCardFields, entity.listFields, entity.fields]);
96
- // Find image field
97
- const imageField = useMemo(() => {
98
- const imageFieldsInList = fieldsToShow.filter((fieldName) => {
99
- const fieldConfig = entity.fields[fieldName];
100
- return fieldConfig?.type === 'image' || fieldConfig?.type === 'images';
101
- });
102
- if (imageFieldsInList.length > 0)
103
- return imageFieldsInList[0];
104
- // Fallback: search all entity fields
105
- const allImageFields = Object.keys(entity.fields).filter((fieldName) => {
106
- const fieldConfig = entity.fields[fieldName];
107
- return fieldConfig?.type === 'image' || fieldConfig?.type === 'images';
108
- });
109
- return allImageFields[0] || null;
110
- }, [fieldsToShow, entity.fields]);
111
- // Get other fields (non-image)
112
- const otherFields = useMemo(() => {
113
- return fieldsToShow.filter((fieldName) => fieldName !== imageField);
114
- }, [fieldsToShow, imageField]);
86
+ // Flat field names for filters (works with both string[] and ListCardLayout)
87
+ const fieldsToFilter = useMemo(() => getListCardFieldNames(entity), [entity]);
115
88
  const entityName = t('name', { defaultValue: entity.name });
116
89
  return (_jsxs(_Fragment, { children: [!hideFilters && (_jsx(Section, { title: tCrud('filters.title', {
117
90
  entity: entityName,
118
91
  defaultValue: `Browse ${entityName} - Filters`,
119
- }), collapsible: true, defaultOpen: true, children: _jsxs(Stack, { direction: "column", children: [_jsx(Button, { variant: showFavoritesOnly ? 'primary' : 'outline', icon: _jsx(Heart, { size: 18 }), onClick: () => setShowFavoritesOnly(!showFavoritesOnly), children: showFavoritesOnly
120
- ? tCrud('favorites.showAll', { defaultValue: 'Show All' })
121
- : tCrud('favorites.showFavorites', {
122
- defaultValue: 'Show Favorites',
123
- }) }), _jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: entity.listCardFields })] }) })), _jsx(Section, { title: loading
92
+ }), collapsible: true, defaultOpen: true, tone: tone, children: _jsx(Card, { children: _jsxs(Stack, { direction: "column", children: [_jsx(Button, { variant: showFavoritesOnly ? 'primary' : 'outline', icon: _jsx(Heart, { size: 18 }), onClick: () => setShowFavoritesOnly(!showFavoritesOnly), children: showFavoritesOnly
93
+ ? tCrud('favorites.showAll', { defaultValue: 'Show All' })
94
+ : tCrud('favorites.showFavorites', {
95
+ defaultValue: 'Show Favorites',
96
+ }) }), _jsx(EntityFilters, { entity: entity, data: rawData, fieldsToFilter: fieldsToFilter })] }) }) })), _jsx(Section, { title: loading
124
97
  ? tCrud('results.title.fetching', { defaultValue: 'Fetching...' })
125
- : tCrud('results.title.count', {
126
- count: data.length,
127
- defaultValue: data.length === 1
128
- ? 'Found 1 occurrence'
129
- : `Found ${data.length} occurrences`,
130
- }), collapsible: true, defaultOpen: true, children: loading ? (_jsx(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)' }, children: _jsx(Spinner, {}) })) : data.length === 0 ? (_jsxs(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)', textAlign: 'center' }, children: [_jsx(Text, { level: "h3", style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.title', {
98
+ : resultLabel
99
+ ? resultLabel(data.length)
100
+ : tCrud('results.title.count', {
101
+ count: data.length,
102
+ defaultValue: data.length === 1
103
+ ? 'Found 1 occurrence'
104
+ : `Found ${data.length} occurrences`,
105
+ }), collapsible: true, defaultOpen: true, tone: tone, children: loading ? (_jsx(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)' }, children: _jsx(Spinner, {}) })) : data.length === 0 ? (_jsxs(Stack, { align: "center", justify: "center", style: { padding: 'var(--gap-3xl)', textAlign: 'center' }, children: [_jsx(Text, { level: "h3", style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.title', {
131
106
  defaultValue: `No ${entity.name.toLowerCase()} found`,
132
107
  }) }), _jsx(Text, { style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.description', {
133
108
  defaultValue: `No ${entity.name.toLowerCase()} available at this time.`,
134
109
  }) })] })) : (_jsx(Grid, { cols: cols, children: data.map((item) => {
135
- const imageValue = imageField ? item[imageField] : null;
136
- // Backend optimizes picture fields for listCard: returns thumbUrl string directly
137
- // (or fullUrl if thumbUrl missing, or null if no picture)
138
- const imageUrl = typeof imageValue === 'string' ? imageValue : null;
139
- // Title from first non-image field
140
- const titleField = otherFields[0];
141
- const titleValue = titleField ? item[titleField] : item.id;
142
110
  const itemIsFavorite = isFavorite(item.id);
143
- return (_jsxs(Card, { title: String(titleValue || ''), clickable: true, onClick: () => handleView(item.id), elevated: true, children: [_jsx(Heart, { fill: itemIsFavorite ? '#ef4444' : '#ffffff', stroke: itemIsFavorite ? '#ef4444' : 'var(--muted-foreground)', onClick: (e) => {
144
- e.stopPropagation();
145
- toggleFavorite(item.id);
146
- }, style: {
147
- position: 'absolute',
148
- top: 'var(--gap-sm)',
149
- right: 'var(--gap-sm)',
150
- zIndex: 10,
151
- cursor: 'pointer',
152
- width: 'var(--icon-md)',
153
- height: 'var(--icon-md)',
154
- transition: 'fill 0.2s, stroke 0.2s',
155
- }, "aria-label": itemIsFavorite
156
- ? tCrud('favorites.remove', {
157
- defaultValue: 'Remove from favorites',
158
- })
159
- : tCrud('favorites.add', {
160
- defaultValue: 'Add to favorites',
161
- }) }), _jsxs(Stack, { direction: "column", children: [imageUrl && (_jsx("div", { style: {
162
- width: '100%',
163
- aspectRatio: '16/9',
164
- borderRadius: 'var(--radius-md)',
165
- overflow: 'hidden',
166
- backgroundColor: 'var(--muted)',
167
- position: 'relative',
168
- }, children: _jsx("img", { src: imageUrl, alt: String(titleValue || ''), style: {
169
- width: '100%',
170
- height: '100%',
171
- objectFit: 'cover',
172
- } }) })), _jsx(Stack, { direction: "column", gap: "tight", children: otherFields.slice(1, 4).map((fieldName) => {
173
- const fieldConfig = entity.fields[fieldName];
174
- if (!fieldConfig)
175
- return null;
176
- return (_jsxs("div", { children: [_jsx(Text, { level: "small", variant: "muted", children: translateFieldLabel(fieldName, fieldConfig, t) }), _jsx(Text, { children: formatValue(item[fieldName], fieldConfig, t, {
177
- compact: true,
178
- }) })] }, fieldName));
179
- }) })] })] }, item.id));
111
+ const detailHref = onClick ? undefined : `${base}/${item.id}`;
112
+ return (_jsx(CrudCard, { item: item, entity: entity, detailHref: detailHref, onClick: onClick ? () => handleView(item.id) : undefined, renderActions: _jsx(Heart, { fill: itemIsFavorite ? '#ef4444' : '#ffffff', stroke: itemIsFavorite ? '#ef4444' : 'var(--muted-foreground)', onClick: (e) => {
113
+ e.preventDefault();
114
+ e.stopPropagation();
115
+ toggleFavorite(item.id);
116
+ }, style: {
117
+ cursor: 'pointer',
118
+ width: 'var(--icon-md)',
119
+ height: 'var(--icon-md)',
120
+ transition: 'fill 0.2s, stroke 0.2s',
121
+ }, "aria-label": itemIsFavorite
122
+ ? tCrud('favorites.remove', {
123
+ defaultValue: 'Remove from favorites',
124
+ })
125
+ : tCrud('favorites.add', {
126
+ defaultValue: 'Add to favorites',
127
+ }) }) }, item.id));
180
128
  }) })) })] }));
181
129
  }
@@ -16,6 +16,6 @@ export type { EntityDisplayRendererProps };
16
16
  * <EntityDisplayRenderer entity={carEntity} id={carId} />
17
17
  * ```
18
18
  */
19
- export declare function EntityDisplayRenderer<T extends EntityRecord = EntityRecord>({ entity, id, t, className, backend, loadingMessage, notFoundMessage, viewerRole, }: EntityDisplayRendererProps<T>): import("react/jsx-runtime").JSX.Element;
19
+ export declare function EntityDisplayRenderer<T extends EntityRecord = EntityRecord>({ entity, id, t, className, loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, excludeFields, }: EntityDisplayRendererProps<T>): import("react/jsx-runtime").JSX.Element;
20
20
  export default EntityDisplayRenderer;
21
21
  //# sourceMappingURL=EntityDisplayRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EntityDisplayRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityDisplayRenderer.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG/E,YAAY,EAAE,0BAA0B,EAAE,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EAC3E,MAAM,EACN,EAAE,EACF,CAAC,EACD,SAAc,EACd,OAAqB,EACrB,cAAc,EACd,eAAe,EACf,UAAoB,GACrB,EAAE,0BAA0B,CAAC,CAAC,CAAC,2CAgM/B;AAED,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"EntityDisplayRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityDisplayRenderer.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI/E,YAAY,EAAE,0BAA0B,EAAE,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EAC3E,MAAM,EACN,EAAE,EACF,CAAC,EACD,SAAc,EACd,cAAc,EACd,eAAe,EACf,UAAU,EAAE,cAAc,EAC1B,aAAa,GACd,EAAE,0BAA0B,CAAC,CAAC,CAAC,2CAuM/B;AAED,eAAe,qBAAqB,CAAC"}
@@ -14,6 +14,7 @@ import { useEffect, useState, useMemo } from 'react';
14
14
  import { Stack, Spinner } from '@donotdev/components';
15
15
  import { useTranslation, isFieldVisible } from '@donotdev/core';
16
16
  import { useCrud, DisplayFieldRenderer } from '@donotdev/crud';
17
+ import { useAuthSafe } from '../../utils/useAuthSafe';
17
18
  /**
18
19
  * EntityDisplayRenderer - Automatically fetches and displays entity data
19
20
  *
@@ -30,8 +31,11 @@ import { useCrud, DisplayFieldRenderer } from '@donotdev/crud';
30
31
  * <EntityDisplayRenderer entity={carEntity} id={carId} />
31
32
  * ```
32
33
  */
33
- export function EntityDisplayRenderer({ entity, id, t, className = '', backend = 'functions', loadingMessage, notFoundMessage, viewerRole = 'guest', }) {
34
- const { get, loading, data: storeData, error: storeError, isAvailable, } = useCrud(entity, { backend });
34
+ export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, excludeFields, }) {
35
+ // Auto-detect role from auth; prop overrides
36
+ const authRole = useAuthSafe('userRole');
37
+ const viewerRole = viewerRoleProp ?? authRole;
38
+ const { get, loading, data: storeData, error: storeError, isAvailable, } = useCrud(entity);
35
39
  const [isFetching, setIsFetching] = useState(false);
36
40
  const [fetchError, setFetchError] = useState(null);
37
41
  const [data, setData] = useState(null);
@@ -91,6 +95,10 @@ export function EntityDisplayRenderer({ entity, id, t, className = '', backend =
91
95
  if (!displayData)
92
96
  return [];
93
97
  return Object.entries(entity.fields).filter(([fieldName, fieldConfig]) => {
98
+ // Skip excluded fields
99
+ if (excludeFields?.includes(fieldName)) {
100
+ return false;
101
+ }
94
102
  // Check visibility first
95
103
  if (!isFieldVisible(fieldConfig.visibility, viewerRole)) {
96
104
  return false;
@@ -122,7 +130,7 @@ export function EntityDisplayRenderer({ entity, id, t, className = '', backend =
122
130
  }
123
131
  return true;
124
132
  });
125
- }, [entity.fields, viewerRole, displayData]);
133
+ }, [entity.fields, viewerRole, displayData, excludeFields]);
126
134
  // Loading state
127
135
  if (isLoading) {
128
136
  return (_jsx("div", { style: {
@@ -13,6 +13,6 @@ export type { EntityFormRendererProps };
13
13
  * @since 0.0.1
14
14
  * @author AMBROISE PARK Consulting
15
15
  */
16
- export declare function EntityFormRenderer<T extends EntityRecord = EntityRecord>({ entity, onSubmit, t, className, submitText, loading, defaultValues, submitVariant, secondaryButtonText, secondaryButtonVariant, onSecondarySubmit, viewerRole, operation, autoSave, formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges, unsavedChangesMessage, hideVisibilityInfo, }: EntityFormRendererProps<T>): import("react/jsx-runtime").JSX.Element;
16
+ export declare function EntityFormRenderer<T extends EntityRecord = EntityRecord>({ entity, onSubmit, t, className, submitText, loading, defaultValues, submitVariant, secondaryButtonText, secondaryButtonVariant, onSecondarySubmit, viewerRole: viewerRoleProp, operation, formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges, unsavedChangesMessage, hideVisibilityInfo, }: EntityFormRendererProps<T>): import("react/jsx-runtime").JSX.Element;
17
17
  export default EntityFormRenderer;
18
18
  //# sourceMappingURL=EntityFormRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EntityFormRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityFormRenderer.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EAEb,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EACxE,MAAM,EACN,QAAQ,EACR,CAAC,EACD,SAAc,EACd,UAAU,EACV,OAAe,EACf,aAAa,EACb,aAAyB,EACzB,mBAAmB,EACnB,sBAAkC,EAClC,iBAAiB,EACjB,UAAU,EACV,SAA6C,EAC7C,QAAiC,EACjC,MAAM,EAAE,cAAc,EACtB,UAAU,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,oBAA2B,EAC3B,qBAAqB,EACrB,kBAA0B,GAC3B,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CAic5B;AAED,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"EntityFormRenderer.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityFormRenderer.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EAEb,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,uBAAuB,EAAE,CAAC;AAExC;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EACxE,MAAM,EACN,QAAQ,EACR,CAAC,EACD,SAAc,EACd,UAAU,EACV,OAAe,EACf,aAAa,EACb,aAAyB,EACzB,mBAAmB,EACnB,sBAAkC,EAClC,iBAAiB,EACjB,UAAU,EAAE,cAAc,EAC1B,SAA6C,EAC7C,MAAM,EAAE,cAAc,EACtB,UAAU,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,oBAA2B,EAC3B,qBAAqB,EACrB,kBAA0B,GAC3B,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CAkb5B;AAED,eAAe,kBAAkB,CAAC"}
@@ -15,7 +15,8 @@ import { FormProvider } from 'react-hook-form';
15
15
  import { Badge, Button, DropdownMenu, Grid, Stack, Spinner, } from '@donotdev/components';
16
16
  import { hasRoleAccess, useTranslation } from '@donotdev/core';
17
17
  import { useNavigate } from '../../routing';
18
- import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm, useUnsavedChangesWarning, useConfirmNavigation, useFormStore, } from '@donotdev/crud';
18
+ import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm, useUnsavedChangesWarning, useFormStore, } from '@donotdev/crud';
19
+ import { useAuthSafe } from '../../utils/useAuthSafe';
19
20
  /**
20
21
  * EntityFormRenderer - Dumb component that renders a form from entity definition.
21
22
  *
@@ -29,8 +30,11 @@ import { DisplayFieldRenderer, FormFieldRenderer, UploadProvider, useEntityForm,
29
30
  * @since 0.0.1
30
31
  * @author AMBROISE PARK Consulting
31
32
  */
32
- export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole, operation = defaultValues ? 'edit' : 'create', autoSave = operation === 'create', formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges = true, unsavedChangesMessage, hideVisibilityInfo = false, }) {
33
+ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole: viewerRoleProp, operation = defaultValues ? 'edit' : 'create', formId: externalFormId, cancelText, cancelPath, successPath, onCancel, warnOnUnsavedChanges = true, unsavedChangesMessage, hideVisibilityInfo = false, }) {
33
34
  const navigate = useNavigate();
35
+ // Auto-detect role from auth; prop overrides (e.g. View-As preview)
36
+ const authRole = useAuthSafe('userRole');
37
+ const viewerRole = viewerRoleProp ?? authRole;
34
38
  // Generate stable form ID
35
39
  const generatedFormId = useId();
36
40
  const formId = externalFormId ?? `entity-form-${entity.name}-${generatedFormId}`;
@@ -81,7 +85,6 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
81
85
  defaultValues,
82
86
  viewerRole,
83
87
  t: translate,
84
- autoSave,
85
88
  });
86
89
  const { control, handleSubmit, formState: { errors }, fields: rawFields, formStatus, uploadProgress, cleanup, isDirty, hasUserInteracted, resetForm, } = form;
87
90
  const isDirtyForBlocking = isDirty && hasUserInteracted;
@@ -102,6 +105,7 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
102
105
  });
103
106
  }, [rawFields, canPreviewRole, previewRole]);
104
107
  // Sync isDirty to FormStore (single source of truth)
108
+ // Use getState() to avoid subscribing to the action reference (Zustand anti-pattern)
105
109
  useEffect(() => {
106
110
  if (formId) {
107
111
  useFormStore.getState().setIsDirty(formId, isDirtyForBlocking);
@@ -116,57 +120,47 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
116
120
  tCrud('messages.unsavedChangesLeave', {
117
121
  defaultValue: 'You have unsaved changes. Are you sure you want to leave?',
118
122
  }), [unsavedChangesMessage, tCrud]);
119
- const unsavedChangesDiscardMessage = useMemo(() => unsavedChangesMessage ||
120
- tCrud('messages.unsavedChangesDiscard', {
121
- defaultValue: 'You have unsaved changes. Discard them?',
122
- }), [unsavedChangesMessage, tCrud]);
123
123
  // Warn about unsaved changes when navigating away (browser refresh/close)
124
- // SPA navigation blocking is handled by router hooks via FormStore
124
+ // beforeunload is the only place we can't toast browser requires native dialog
125
125
  useUnsavedChangesWarning({
126
126
  isDirty: isDirtyForBlocking,
127
127
  enabled: warnOnUnsavedChanges,
128
128
  message: unsavedChangesLeaveMessage,
129
129
  });
130
- // Use framework helper for cancel confirmation (DRY, SSR-safe)
131
- const confirmNavigation = useConfirmNavigation(isDirtyForBlocking, unsavedChangesDiscardMessage);
132
- // Handle cancel with confirmation
133
- const handleCancel = async () => {
134
- if (isDirtyForBlocking) {
135
- const confirmed = await confirmNavigation();
136
- if (!confirmed)
137
- return;
138
- }
130
+ // Handle cancel auto-save ensures draft is persisted, no confirm needed
131
+ const handleCancel = () => {
139
132
  resetForm();
140
- // If onCancel callback provided, use it (takes precedence)
141
133
  if (onCancel) {
142
134
  onCancel();
143
135
  }
136
+ else if (cancelPath) {
137
+ navigate(cancelPath);
138
+ }
144
139
  else {
145
- // Otherwise, navigate back or to cancelPath if provided
146
- if (cancelPath) {
147
- navigate(cancelPath);
148
- }
149
- else {
150
- navigate('back');
151
- }
140
+ navigate('back');
152
141
  }
153
142
  };
154
- // Wrap onSubmit to navigate optimistically (fire and forget)
143
+ // Wrap onSubmit to await the result before navigating
155
144
  // handleSubmit from react-hook-form expects: (data: EntityData) => void | Promise<void>
156
145
  // Our onSubmit prop is (data: T) => void | Promise<void>, where T extends EntityRecord
157
146
  // EntityData should be compatible with T, so we can safely pass it
158
- const handleFormSubmit = (data) => {
159
- // Call onSubmit (don't await - optimistic update pattern)
160
- // Type assertion is safe: EntityData is the validated form data, T is EntityRecord
161
- onSubmit(data);
162
- // Navigate immediately (optimistic navigation - feels fast)
163
- // If onSubmit is async, navigation happens while it's processing in background
164
- if (successPath) {
165
- navigate(successPath);
147
+ const handleFormSubmit = async (data) => {
148
+ try {
149
+ // Await onSubmit so navigation only happens after successful submission
150
+ // Type assertion is safe: EntityData is the validated form data, T is EntityRecord
151
+ await onSubmit(data);
152
+ // Navigate only after successful submission
153
+ if (successPath) {
154
+ navigate(successPath);
155
+ }
156
+ else {
157
+ // Default: navigate back (user came from list, go back there)
158
+ navigate('back');
159
+ }
166
160
  }
167
- else {
168
- // Default: navigate back (optimistic - user came from list, go back there)
169
- navigate('back');
161
+ catch {
162
+ // onSubmit rejected stay on form so user can correct errors
163
+ // Error display is handled by the caller's onSubmit implementation
170
164
  }
171
165
  };
172
166
  // Determine if cancel button should show
@@ -274,13 +268,13 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
274
268
  if (buttonCount === 1) {
275
269
  return (_jsx(Stack, { direction: "column", gap: "tight", style: buttonContainerStyle, children: buttons[0] }));
276
270
  }
277
- // Multiple buttons: use Grid with proportional columns (Submit gets 2fr)
278
- const templateColumns = buttonCount === 2
271
+ // Multiple buttons: responsive stacked on mobile, proportional on tablet+
272
+ const colTemplate = buttonCount === 2
279
273
  ? '1fr 2fr' // Cancel/Preview + Submit
280
274
  : buttonCount === 3
281
275
  ? '1fr 1fr 2fr' // Cancel + Preview + Submit
282
276
  : '1fr 1fr 1fr 2fr'; // Cancel + Preview + Secondary + Submit
283
- return (_jsx(Grid, { cols: [1, buttonCount, buttonCount, buttonCount], templateColumns: templateColumns, gap: "tight", style: buttonContainerStyle, children: buttons }));
277
+ return (_jsx(Grid, { cols: ['1fr', colTemplate, colTemplate, colTemplate], gap: "tight", style: buttonContainerStyle, children: buttons }));
284
278
  })()] })] }) }) }));
285
279
  }
286
280
  export default EntityFormRenderer;
@@ -10,5 +10,5 @@ export type { EntityListProps };
10
10
  * - Edit and Delete actions (admin only)
11
11
  * - Auto-routing when handlers not provided
12
12
  */
13
- export declare function EntityList({ entity, userRole, basePath, onClick, hideFilters, pagination, pageSize: pageSizeProp, queryOptions, exportable, }: EntityListProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function EntityList({ entity, basePath, onClick, hideFilters, pagination, pageSize: pageSizeProp, queryOptions, exportable, }: EntityListProps): import("react/jsx-runtime").JSX.Element;
14
14
  //# sourceMappingURL=EntityList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAkB,EAClB,QAAQ,EACR,OAAO,EACP,WAAmB,EACnB,UAAqB,EACrB,QAAQ,EAAE,YAAY,EACtB,YAAY,EACZ,UAAiB,GAClB,EAAE,eAAe,2CAkTjB"}
1
+ {"version":3,"file":"EntityList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityList.tsx"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,QAAQ,EACR,OAAO,EACP,WAAmB,EACnB,UAAqB,EACrB,QAAQ,EAAE,YAAY,EACtB,YAAY,EACZ,UAAiB,GAClB,EAAE,eAAe,2CAiTjB"}
@@ -29,7 +29,7 @@ import { translateFieldLabel, useCrud, useCrudList, EntityFilters, matchesFilter
29
29
  * - Edit and Delete actions (admin only)
30
30
  * - Auto-routing when handlers not provided
31
31
  */
32
- export function EntityList({ entity, userRole = 'guest', basePath, onClick, hideFilters = false, pagination = 'client', pageSize: pageSizeProp, queryOptions, exportable = true, }) {
32
+ export function EntityList({ entity, basePath, onClick, hideFilters = false, pagination = 'client', pageSize: pageSizeProp, queryOptions, exportable = true, }) {
33
33
  const navigate = useNavigate();
34
34
  const base = basePath ?? `/${entity.collection}`;
35
35
  // Server-side pagination state (only used when pagination='server')
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview Reusable recommendations section for related entities
3
+ * @description Fetches and displays related entity cards in a grid.
4
+ * Caller defines "related by what" via queryOptions.
5
+ *
6
+ * @version 0.0.1
7
+ * @since 0.0.15
8
+ * @author AMBROISE PARK Consulting
9
+ */
10
+ import type { EntityRecommendationsProps } from '@donotdev/core';
11
+ /**
12
+ * Displays a grid of related entity cards.
13
+ * Uses useCrudCardList (listCard schema) so cards render identically to EntityCardList.
14
+ *
15
+ * @example
16
+ * <EntityRecommendations
17
+ * entity={apartmentEntity}
18
+ * title={t('apartment.recommendations')}
19
+ * queryOptions={{
20
+ * where: [
21
+ * { field: 'district_code', operator: 'eq', value: current.district_code },
22
+ * { field: 'id', operator: 'neq', value: current.id },
23
+ * ],
24
+ * limit: 3,
25
+ * }}
26
+ * />
27
+ */
28
+ export declare function EntityRecommendations({ entity, queryOptions, title, basePath, cols, className, }: EntityRecommendationsProps): import("react/jsx-runtime").JSX.Element | null;
29
+ //# sourceMappingURL=EntityRecommendations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityRecommendations.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityRecommendations.tsx"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAMjE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,IAAQ,EACR,SAAS,GACV,EAAE,0BAA0B,kDAuB5B"}
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Section } from '@donotdev/components';
4
+ import { useCrudCardList } from '@donotdev/crud';
5
+ import { CrudCard } from './CrudCardLink';
6
+ /**
7
+ * Displays a grid of related entity cards.
8
+ * Uses useCrudCardList (listCard schema) so cards render identically to EntityCardList.
9
+ *
10
+ * @example
11
+ * <EntityRecommendations
12
+ * entity={apartmentEntity}
13
+ * title={t('apartment.recommendations')}
14
+ * queryOptions={{
15
+ * where: [
16
+ * { field: 'district_code', operator: 'eq', value: current.district_code },
17
+ * { field: 'id', operator: 'neq', value: current.id },
18
+ * ],
19
+ * limit: 3,
20
+ * }}
21
+ * />
22
+ */
23
+ export function EntityRecommendations({ entity, queryOptions, title, basePath, cols = 3, className, }) {
24
+ const { items, loading } = useCrudCardList(entity, {
25
+ queryOptions,
26
+ });
27
+ if (!loading && items.length === 0) {
28
+ return null;
29
+ }
30
+ const resolvedBasePath = basePath ?? `/${entity.collection}`;
31
+ return (_jsx(Section, { title: title, gridCols: cols, className: className, children: items.map((item) => (_jsx(CrudCard, { item: item, entity: entity, detailHref: `${resolvedBasePath}/${item.id}` }, item.id))) }));
32
+ }
@@ -10,6 +10,7 @@ export { EntityDisplayRenderer } from './EntityDisplayRenderer';
10
10
  export { EntityList } from './EntityList';
11
11
  export { EntityCardList } from './EntityCardList';
12
12
  export { EntityFormRenderer } from './EntityFormRenderer';
13
+ export { EntityRecommendations } from './EntityRecommendations';
13
14
  export * from './Form';
14
- export type { EntityListProps, EntityCardListProps, EntityFormRendererProps, EntityDisplayRendererProps, } from '@donotdev/core';
15
+ export type { EntityListProps, EntityCardListProps, EntityRecommendationsProps, EntityFormRendererProps, EntityDisplayRendererProps, } from '@donotdev/core';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crud/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,cAAc,QAAQ,CAAC;AAEvB,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crud/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,cAAc,QAAQ,CAAC;AAEvB,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC"}
@@ -11,4 +11,5 @@ export { EntityDisplayRenderer } from './EntityDisplayRenderer';
11
11
  export { EntityList } from './EntityList';
12
12
  export { EntityCardList } from './EntityCardList';
13
13
  export { EntityFormRenderer } from './EntityFormRenderer';
14
+ export { EntityRecommendations } from './EntityRecommendations';
14
15
  export * from './Form';