@donotdev/ui 0.0.14 → 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 (41) hide show
  1. package/dist/components/layout/components/index.d.ts +3 -0
  2. package/dist/components/layout/components/index.d.ts.map +1 -1
  3. package/dist/components/layout/components/index.js +3 -0
  4. package/dist/crud/components/EntityCardList.d.ts +1 -1
  5. package/dist/crud/components/EntityCardList.d.ts.map +1 -1
  6. package/dist/crud/components/EntityCardList.js +16 -13
  7. package/dist/crud/components/EntityDisplayRenderer.d.ts +1 -1
  8. package/dist/crud/components/EntityDisplayRenderer.d.ts.map +1 -1
  9. package/dist/crud/components/EntityDisplayRenderer.js +6 -2
  10. package/dist/crud/components/EntityFormRenderer.d.ts +1 -1
  11. package/dist/crud/components/EntityFormRenderer.d.ts.map +1 -1
  12. package/dist/crud/components/EntityFormRenderer.js +12 -29
  13. package/dist/crud/components/EntityRecommendations.d.ts +1 -0
  14. package/dist/crud/components/EntityRecommendations.d.ts.map +1 -1
  15. package/dist/crud/components/EntityRecommendations.js +3 -2
  16. package/dist/dndev.css +11558 -0
  17. package/dist/index.js +4 -4
  18. package/dist/internal/providers/NavigationProvider.d.ts.map +1 -1
  19. package/dist/internal/providers/NavigationProvider.js +3 -5
  20. package/dist/providers/ViteAppProviders.d.ts.map +1 -1
  21. package/dist/providers/ViteAppProviders.js +3 -5
  22. package/dist/routing/GoToInput.d.ts.map +1 -1
  23. package/dist/routing/GoToInput.js +4 -5
  24. package/dist/routing/hooks/hooks.next.js +1 -1
  25. package/dist/routing/hooks/hooks.vite.js +1 -1
  26. package/dist/routing/hooks/useNavigate.next.d.ts +1 -1
  27. package/dist/routing/hooks/useNavigate.next.d.ts.map +1 -1
  28. package/dist/routing/hooks/useNavigate.next.js +1 -7
  29. package/dist/routing/hooks/useNavigate.vite.d.ts +1 -1
  30. package/dist/routing/hooks/useNavigate.vite.d.ts.map +1 -1
  31. package/dist/routing/hooks/useNavigate.vite.js +1 -7
  32. package/dist/routing/useRouteDiscovery.d.ts +4 -15
  33. package/dist/routing/useRouteDiscovery.d.ts.map +1 -1
  34. package/dist/routing/useRouteDiscovery.js +6 -5
  35. package/dist/styles/index.css +16 -6
  36. package/dist/utils/useFormStoreSafe.d.ts +2 -15
  37. package/dist/utils/useFormStoreSafe.d.ts.map +1 -1
  38. package/dist/utils/useFormStoreSafe.js +3 -33
  39. package/dist/vite-routing/RootLayout.d.ts.map +1 -1
  40. package/dist/vite-routing/RootLayout.js +10 -15
  41. package/package.json +10 -10
@@ -19,4 +19,7 @@ export { default as HeaderNavigation } from './header/HeaderNavigation';
19
19
  export { default as Notifications } from './Notifications';
20
20
  export { default as SettingsMenu } from './header/SettingsMenu';
21
21
  export { default as ThemeToggle } from './header/ThemeToggle';
22
+ export { FooterBranding } from '../../../internal/layout/components/footer/FooterBranding';
23
+ export { FooterCopyright } from '../../../internal/layout/components/footer/FooterCopyright';
24
+ export { FooterLegalLinks } from '../../../internal/layout/components/footer/FooterLegalLinks';
22
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,2DAA2D,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,4DAA4D,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,MAAM,6DAA6D,CAAC"}
@@ -20,3 +20,6 @@ export { default as HeaderNavigation } from './header/HeaderNavigation';
20
20
  export { default as Notifications } from './Notifications';
21
21
  export { default as SettingsMenu } from './header/SettingsMenu';
22
22
  export { default as ThemeToggle } from './header/ThemeToggle';
23
+ export { FooterBranding } from '../../../internal/layout/components/footer/FooterBranding';
24
+ export { FooterCopyright } from '../../../internal/layout/components/footer/FooterCopyright';
25
+ export { FooterLegalLinks } from '../../../internal/layout/components/footer/FooterLegalLinks';
@@ -12,5 +12,5 @@ export type { EntityCardListProps };
12
12
  * - Auto-routing when handler not provided
13
13
  */
14
14
  export declare function EntityCardList({ entity, basePath, onClick, cols, staleTime, // 30 minutes default cache
15
- filter, hideFilters, }: EntityCardListProps): import("react/jsx-runtime").JSX.Element;
15
+ filter, hideFilters, resultLabel, tone, }: EntityCardListProps): import("react/jsx-runtime").JSX.Element;
16
16
  //# sourceMappingURL=EntityCardList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EntityCardList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityCardList.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,MAAM,gBAAgB,CAAC;AAIxE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAmB,EACnB,SAA0B,EAAE,2BAA2B;AACvD,MAAM,EACN,WAAmB,GACpB,EAAE,mBAAmB,2CAqMrB"}
1
+ {"version":3,"file":"EntityCardList.d.ts","sourceRoot":"","sources":["../../../src/crud/components/EntityCardList.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,MAAM,gBAAgB,CAAC;AAIxE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAmB,EACnB,SAA0B,EAAE,2BAA2B;AACvD,MAAM,EACN,WAAmB,EACnB,WAAW,EACX,IAAI,GACL,EAAE,mBAAmB,2CA4MrB"}
@@ -15,7 +15,7 @@ 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, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
18
+ import { Card, Grid, Stack, Text, Spinner, Section, Button, } from '@donotdev/components';
19
19
  import { useTranslation, getListCardFieldNames } from '@donotdev/core';
20
20
  import { useNavigate } from '../../routing';
21
21
  import { useCrudCardList, EntityFilters, useEntityFavorites, matchesFilter, useCrudFilters, } from '@donotdev/crud';
@@ -32,7 +32,7 @@ import { CrudCard } from './CrudCardLink';
32
32
  * - Auto-routing when handler not provided
33
33
  */
34
34
  export function EntityCardList({ entity, basePath, onClick, cols = [1, 2, 3, 4], staleTime = 1000 * 60 * 30, // 30 minutes default cache
35
- filter, hideFilters = false, }) {
35
+ filter, hideFilters = false, resultLabel, tone, }) {
36
36
  const navigate = useNavigate();
37
37
  const base = basePath ?? `/${entity.collection}`;
38
38
  // useCrudCardList -> handles fetching optimized for cards automatically
@@ -89,18 +89,20 @@ filter, hideFilters = false, }) {
89
89
  return (_jsxs(_Fragment, { children: [!hideFilters && (_jsx(Section, { title: tCrud('filters.title', {
90
90
  entity: entityName,
91
91
  defaultValue: `Browse ${entityName} - Filters`,
92
- }), 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
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
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
97
97
  ? tCrud('results.title.fetching', { defaultValue: 'Fetching...' })
98
- : tCrud('results.title.count', {
99
- count: data.length,
100
- defaultValue: data.length === 1
101
- ? 'Found 1 occurrence'
102
- : `Found ${data.length} occurrences`,
103
- }), 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', {
104
106
  defaultValue: `No ${entity.name.toLowerCase()} found`,
105
107
  }) }), _jsx(Text, { style: { color: 'var(--muted-foreground)' }, children: tCrud('emptyState.description', {
106
108
  defaultValue: `No ${entity.name.toLowerCase()} available at this time.`,
@@ -108,6 +110,7 @@ filter, hideFilters = false, }) {
108
110
  const itemIsFavorite = isFavorite(item.id);
109
111
  const detailHref = onClick ? undefined : `${base}/${item.id}`;
110
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();
111
114
  e.stopPropagation();
112
115
  toggleFavorite(item.id);
113
116
  }, style: {
@@ -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, loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, }: 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;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,GAC3B,EAAE,0BAA0B,CAAC,CAAC,CAAC,2CAkM/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"}
@@ -31,7 +31,7 @@ import { useAuthSafe } from '../../utils/useAuthSafe';
31
31
  * <EntityDisplayRenderer entity={carEntity} id={carId} />
32
32
  * ```
33
33
  */
34
- export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, }) {
34
+ export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMessage, notFoundMessage, viewerRole: viewerRoleProp, excludeFields, }) {
35
35
  // Auto-detect role from auth; prop overrides
36
36
  const authRole = useAuthSafe('userRole');
37
37
  const viewerRole = viewerRoleProp ?? authRole;
@@ -95,6 +95,10 @@ export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMe
95
95
  if (!displayData)
96
96
  return [];
97
97
  return Object.entries(entity.fields).filter(([fieldName, fieldConfig]) => {
98
+ // Skip excluded fields
99
+ if (excludeFields?.includes(fieldName)) {
100
+ return false;
101
+ }
98
102
  // Check visibility first
99
103
  if (!isFieldVisible(fieldConfig.visibility, viewerRole)) {
100
104
  return false;
@@ -126,7 +130,7 @@ export function EntityDisplayRenderer({ entity, id, t, className = '', loadingMe
126
130
  }
127
131
  return true;
128
132
  });
129
- }, [entity.fields, viewerRole, displayData]);
133
+ }, [entity.fields, viewerRole, displayData, excludeFields]);
130
134
  // Loading state
131
135
  if (isLoading) {
132
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: viewerRoleProp, 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":"AAuCA,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,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,2CA4c5B;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,7 @@ 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
19
  import { useAuthSafe } from '../../utils/useAuthSafe';
20
20
  /**
21
21
  * EntityFormRenderer - Dumb component that renders a form from entity definition.
@@ -30,7 +30,7 @@ import { useAuthSafe } from '../../utils/useAuthSafe';
30
30
  * @since 0.0.1
31
31
  * @author AMBROISE PARK Consulting
32
32
  */
33
- export function EntityFormRenderer({ entity, onSubmit, t, className = '', submitText, loading = false, defaultValues, submitVariant = 'primary', secondaryButtonText, secondaryButtonVariant = 'outline', onSecondarySubmit, viewerRole: viewerRoleProp, 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, }) {
34
34
  const navigate = useNavigate();
35
35
  // Auto-detect role from auth; prop overrides (e.g. View-As preview)
36
36
  const authRole = useAuthSafe('userRole');
@@ -85,7 +85,6 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
85
85
  defaultValues,
86
86
  viewerRole,
87
87
  t: translate,
88
- autoSave,
89
88
  });
90
89
  const { control, handleSubmit, formState: { errors }, fields: rawFields, formStatus, uploadProgress, cleanup, isDirty, hasUserInteracted, resetForm, } = form;
91
90
  const isDirtyForBlocking = isDirty && hasUserInteracted;
@@ -105,14 +104,13 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
105
104
  return fieldRoleIndex <= previewRoleIndex;
106
105
  });
107
106
  }, [rawFields, canPreviewRole, previewRole]);
108
- // Subscribe to setIsDirty action via React-compatible selector
109
- const setFormIsDirty = useFormStore((state) => state.setIsDirty);
110
107
  // Sync isDirty to FormStore (single source of truth)
108
+ // Use getState() to avoid subscribing to the action reference (Zustand anti-pattern)
111
109
  useEffect(() => {
112
110
  if (formId) {
113
- setFormIsDirty(formId, isDirtyForBlocking);
111
+ useFormStore.getState().setIsDirty(formId, isDirtyForBlocking);
114
112
  }
115
- }, [formId, isDirtyForBlocking, setFormIsDirty]);
113
+ }, [formId, isDirtyForBlocking]);
116
114
  // Cleanup on unmount
117
115
  useEffect(() => {
118
116
  return cleanup;
@@ -122,39 +120,24 @@ export function EntityFormRenderer({ entity, onSubmit, t, className = '', submit
122
120
  tCrud('messages.unsavedChangesLeave', {
123
121
  defaultValue: 'You have unsaved changes. Are you sure you want to leave?',
124
122
  }), [unsavedChangesMessage, tCrud]);
125
- const unsavedChangesDiscardMessage = useMemo(() => unsavedChangesMessage ||
126
- tCrud('messages.unsavedChangesDiscard', {
127
- defaultValue: 'You have unsaved changes. Discard them?',
128
- }), [unsavedChangesMessage, tCrud]);
129
123
  // Warn about unsaved changes when navigating away (browser refresh/close)
130
- // SPA navigation blocking is handled by router hooks via FormStore
124
+ // beforeunload is the only place we can't toast browser requires native dialog
131
125
  useUnsavedChangesWarning({
132
126
  isDirty: isDirtyForBlocking,
133
127
  enabled: warnOnUnsavedChanges,
134
128
  message: unsavedChangesLeaveMessage,
135
129
  });
136
- // Use framework helper for cancel confirmation (DRY, SSR-safe)
137
- const confirmNavigation = useConfirmNavigation(isDirtyForBlocking, unsavedChangesDiscardMessage);
138
- // Handle cancel with confirmation
139
- const handleCancel = async () => {
140
- if (isDirtyForBlocking) {
141
- const confirmed = await confirmNavigation();
142
- if (!confirmed)
143
- return;
144
- }
130
+ // Handle cancel auto-save ensures draft is persisted, no confirm needed
131
+ const handleCancel = () => {
145
132
  resetForm();
146
- // If onCancel callback provided, use it (takes precedence)
147
133
  if (onCancel) {
148
134
  onCancel();
149
135
  }
136
+ else if (cancelPath) {
137
+ navigate(cancelPath);
138
+ }
150
139
  else {
151
- // Otherwise, navigate back or to cancelPath if provided
152
- if (cancelPath) {
153
- navigate(cancelPath);
154
- }
155
- else {
156
- navigate('back');
157
- }
140
+ navigate('back');
158
141
  }
159
142
  };
160
143
  // Wrap onSubmit to await the result before navigating
@@ -10,6 +10,7 @@
10
10
  import type { EntityRecommendationsProps } from '@donotdev/core';
11
11
  /**
12
12
  * Displays a grid of related entity cards.
13
+ * Uses useCrudCardList (listCard schema) so cards render identically to EntityCardList.
13
14
  *
14
15
  * @example
15
16
  * <EntityRecommendations
@@ -1 +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;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,IAAQ,EACR,SAAS,GACV,EAAE,0BAA0B,kDAuB5B"}
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"}
@@ -1,10 +1,11 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { Section } from '@donotdev/components';
4
- import { useCrudList } from '@donotdev/crud';
4
+ import { useCrudCardList } from '@donotdev/crud';
5
5
  import { CrudCard } from './CrudCardLink';
6
6
  /**
7
7
  * Displays a grid of related entity cards.
8
+ * Uses useCrudCardList (listCard schema) so cards render identically to EntityCardList.
8
9
  *
9
10
  * @example
10
11
  * <EntityRecommendations
@@ -20,7 +21,7 @@ import { CrudCard } from './CrudCardLink';
20
21
  * />
21
22
  */
22
23
  export function EntityRecommendations({ entity, queryOptions, title, basePath, cols = 3, className, }) {
23
- const { items, loading } = useCrudList(entity, {
24
+ const { items, loading } = useCrudCardList(entity, {
24
25
  queryOptions,
25
26
  });
26
27
  if (!loading && items.length === 0) {