@donotdev/crud 0.0.4 → 0.0.6

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 (150) hide show
  1. package/dist/CrudService.d.ts +7 -3
  2. package/dist/CrudService.d.ts.map +1 -1
  3. package/dist/CrudService.js +1 -1
  4. package/dist/CrudStore.d.ts +6 -1
  5. package/dist/CrudStore.d.ts.map +1 -1
  6. package/dist/CrudStore.js +1 -1
  7. package/dist/FieldRegistry.d.ts +126 -0
  8. package/dist/FieldRegistry.d.ts.map +1 -0
  9. package/dist/FieldRegistry.js +1 -0
  10. package/dist/adapters/FirestoreAdapter.d.ts.map +1 -1
  11. package/dist/adapters/FirestoreAdapter.js +1 -1
  12. package/dist/builtinFieldTypes.d.ts +5 -0
  13. package/dist/builtinFieldTypes.d.ts.map +1 -0
  14. package/dist/builtinFieldTypes.js +1 -0
  15. package/dist/components/ControlledFields.d.ts +42 -24
  16. package/dist/components/ControlledFields.d.ts.map +1 -1
  17. package/dist/components/ControlledFields.js +1 -1
  18. package/dist/components/DisplayFieldRenderer.d.ts +36 -0
  19. package/dist/components/DisplayFieldRenderer.d.ts.map +1 -0
  20. package/dist/components/DisplayFieldRenderer.js +1 -0
  21. package/dist/components/EntityFormRenderer.d.ts +36 -8
  22. package/dist/components/EntityFormRenderer.d.ts.map +1 -1
  23. package/dist/components/EntityFormRenderer.js +5 -1
  24. package/dist/components/FormFieldRenderer.d.ts +3 -16
  25. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  26. package/dist/components/FormFieldRenderer.js +1 -1
  27. package/dist/components/form/fields/AddressFieldComponent.d.ts +3 -1
  28. package/dist/components/form/fields/AddressFieldComponent.d.ts.map +1 -1
  29. package/dist/components/form/fields/AddressFieldComponent.js +1 -1
  30. package/dist/components/form/fields/CheckboxFieldComponent.d.ts +2 -0
  31. package/dist/components/form/fields/CheckboxFieldComponent.d.ts.map +1 -1
  32. package/dist/components/form/fields/CheckboxFieldComponent.js +1 -1
  33. package/dist/components/form/fields/ComboboxComponent.d.ts +43 -0
  34. package/dist/components/form/fields/ComboboxComponent.d.ts.map +1 -0
  35. package/dist/components/form/fields/ComboboxComponent.js +1 -0
  36. package/dist/components/form/fields/CurrencyFieldComponent.d.ts +41 -0
  37. package/dist/components/form/fields/CurrencyFieldComponent.d.ts.map +1 -0
  38. package/dist/components/form/fields/CurrencyFieldComponent.js +1 -0
  39. package/dist/components/form/fields/DateFieldComponent.d.ts +2 -0
  40. package/dist/components/form/fields/DateFieldComponent.d.ts.map +1 -1
  41. package/dist/components/form/fields/DateFieldComponent.js +1 -1
  42. package/dist/components/form/fields/DropdownComponent.d.ts.map +1 -1
  43. package/dist/components/form/fields/DropdownComponent.js +1 -1
  44. package/dist/components/form/fields/FileFieldComponent.d.ts +2 -0
  45. package/dist/components/form/fields/FileFieldComponent.d.ts.map +1 -1
  46. package/dist/components/form/fields/FileFieldComponent.js +1 -1
  47. package/dist/components/form/fields/GeoPointFieldComponent.d.ts +2 -0
  48. package/dist/components/form/fields/GeoPointFieldComponent.d.ts.map +1 -1
  49. package/dist/components/form/fields/GeoPointFieldComponent.js +1 -1
  50. package/dist/components/form/fields/ImageFieldComponent.d.ts +32 -17
  51. package/dist/components/form/fields/ImageFieldComponent.d.ts.map +1 -1
  52. package/dist/components/form/fields/ImageFieldComponent.js +1 -1
  53. package/dist/components/form/fields/MapFieldComponent.d.ts +2 -0
  54. package/dist/components/form/fields/MapFieldComponent.d.ts.map +1 -1
  55. package/dist/components/form/fields/MapFieldComponent.js +1 -1
  56. package/dist/components/form/fields/MultiDropdownComponent.d.ts +2 -2
  57. package/dist/components/form/fields/MultiDropdownComponent.d.ts.map +1 -1
  58. package/dist/components/form/fields/MultiDropdownComponent.js +1 -1
  59. package/dist/components/form/fields/MultiInputTextFieldComponent.d.ts +2 -0
  60. package/dist/components/form/fields/MultiInputTextFieldComponent.d.ts.map +1 -1
  61. package/dist/components/form/fields/MultiInputTextFieldComponent.js +1 -1
  62. package/dist/components/form/fields/NumberFieldComponent.d.ts.map +1 -1
  63. package/dist/components/form/fields/NumberFieldComponent.js +1 -1
  64. package/dist/components/form/fields/PasswordFieldComponent.d.ts.map +1 -1
  65. package/dist/components/form/fields/PasswordFieldComponent.js +1 -1
  66. package/dist/components/form/fields/PhoneNumberComponent.d.ts +31 -17
  67. package/dist/components/form/fields/PhoneNumberComponent.d.ts.map +1 -1
  68. package/dist/components/form/fields/PhoneNumberComponent.js +1 -1
  69. package/dist/components/form/fields/RadioFieldComponent.d.ts.map +1 -1
  70. package/dist/components/form/fields/RadioFieldComponent.js +1 -1
  71. package/dist/components/form/fields/RangeFieldComponent.d.ts.map +1 -1
  72. package/dist/components/form/fields/RangeFieldComponent.js +1 -1
  73. package/dist/components/form/fields/ReferenceFieldComponent.d.ts +7 -2
  74. package/dist/components/form/fields/ReferenceFieldComponent.d.ts.map +1 -1
  75. package/dist/components/form/fields/ReferenceFieldComponent.js +1 -1
  76. package/dist/components/form/fields/SwitchFieldComponent.d.ts +28 -0
  77. package/dist/components/form/fields/SwitchFieldComponent.d.ts.map +1 -0
  78. package/dist/components/form/fields/SwitchFieldComponent.js +1 -0
  79. package/dist/components/form/fields/TextAreaComponent.d.ts.map +1 -1
  80. package/dist/components/form/fields/TextAreaComponent.js +1 -1
  81. package/dist/components/form/fields/TextFieldComponent.d.ts.map +1 -1
  82. package/dist/components/form/fields/TextFieldComponent.js +1 -1
  83. package/dist/components/form/fields/TimestampFieldComponent.d.ts +2 -0
  84. package/dist/components/form/fields/TimestampFieldComponent.d.ts.map +1 -1
  85. package/dist/components/form/fields/TimestampFieldComponent.js +1 -1
  86. package/dist/components/form/fields/index.d.ts +7 -1
  87. package/dist/components/form/fields/index.d.ts.map +1 -1
  88. package/dist/components/form/fields/index.js +1 -1
  89. package/dist/components/form/internal/ImageViewerDialog.d.ts +25 -0
  90. package/dist/components/form/internal/ImageViewerDialog.d.ts.map +1 -0
  91. package/dist/components/form/internal/ImageViewerDialog.js +1 -0
  92. package/dist/components/index.d.ts +2 -0
  93. package/dist/components/index.d.ts.map +1 -1
  94. package/dist/components/index.js +1 -1
  95. package/dist/context/FormUploadContext.d.ts +36 -0
  96. package/dist/context/FormUploadContext.d.ts.map +1 -0
  97. package/dist/context/FormUploadContext.js +1 -0
  98. package/dist/context/index.d.ts +2 -0
  99. package/dist/context/index.d.ts.map +1 -0
  100. package/dist/context/index.js +1 -0
  101. package/dist/forms/hooks/index.d.ts +11 -0
  102. package/dist/forms/hooks/index.d.ts.map +1 -0
  103. package/dist/forms/hooks/index.js +1 -0
  104. package/dist/forms/hooks/useEntityField.d.ts +67 -0
  105. package/dist/forms/hooks/useEntityField.d.ts.map +1 -0
  106. package/dist/forms/hooks/useEntityField.js +1 -0
  107. package/dist/forms/hooks/useEntityForm.d.ts +89 -0
  108. package/dist/forms/hooks/useEntityForm.d.ts.map +1 -0
  109. package/dist/forms/hooks/useEntityForm.js +1 -0
  110. package/dist/forms/index.d.ts +37 -0
  111. package/dist/forms/index.d.ts.map +1 -0
  112. package/dist/forms/index.js +1 -0
  113. package/dist/forms/types.d.ts +185 -0
  114. package/dist/forms/types.d.ts.map +1 -0
  115. package/dist/forms/types.js +0 -0
  116. package/dist/forms/utils/createEntitySchema.d.ts +53 -0
  117. package/dist/forms/utils/createEntitySchema.d.ts.map +1 -0
  118. package/dist/forms/utils/createEntitySchema.js +1 -0
  119. package/dist/forms/utils/getFieldsForOperation.d.ts +87 -0
  120. package/dist/forms/utils/getFieldsForOperation.d.ts.map +1 -0
  121. package/dist/forms/utils/getFieldsForOperation.js +1 -0
  122. package/dist/forms/utils/index.d.ts +14 -0
  123. package/dist/forms/utils/index.d.ts.map +1 -0
  124. package/dist/forms/utils/index.js +1 -0
  125. package/dist/forms/utils/isFieldEditable.d.ts +43 -0
  126. package/dist/forms/utils/isFieldEditable.d.ts.map +1 -0
  127. package/dist/forms/utils/isFieldEditable.js +1 -0
  128. package/dist/forms/utils/normalizeToFieldConfig.d.ts +47 -0
  129. package/dist/forms/utils/normalizeToFieldConfig.d.ts.map +1 -0
  130. package/dist/forms/utils/normalizeToFieldConfig.js +1 -0
  131. package/dist/forms/utils/validateEntity.d.ts +77 -0
  132. package/dist/forms/utils/validateEntity.d.ts.map +1 -0
  133. package/dist/forms/utils/validateEntity.js +1 -0
  134. package/dist/index.d.ts +4 -1
  135. package/dist/index.d.ts.map +1 -1
  136. package/dist/index.js +1 -1
  137. package/dist/tsconfig.tsbuildinfo +1 -1
  138. package/dist/useCrud.d.ts +67 -15
  139. package/dist/useCrud.d.ts.map +1 -1
  140. package/dist/useCrud.js +1 -1
  141. package/dist/utils/imageProcessing.d.ts +49 -0
  142. package/dist/utils/imageProcessing.d.ts.map +1 -0
  143. package/dist/utils/imageProcessing.js +1 -0
  144. package/dist/utils/imageStorage.d.ts +35 -0
  145. package/dist/utils/imageStorage.d.ts.map +1 -0
  146. package/dist/utils/imageStorage.js +1 -0
  147. package/dist/utils/imageUtils.d.ts +86 -0
  148. package/dist/utils/imageUtils.d.ts.map +1 -0
  149. package/dist/utils/imageUtils.js +1 -0
  150. package/package.json +10 -7
package/dist/useCrud.d.ts CHANGED
@@ -1,42 +1,94 @@
1
- import type { dndevSchema, FeatureStatus } from '@donotdev/core';
1
+ import type { dndevSchema, Entity, FeatureStatus } from '@donotdev/core';
2
2
  import { type BackendType } from './CrudStore';
3
3
  import { type QueryOptions } from './CrudService';
4
4
  export interface UseCrudOptions<T> {
5
5
  backend?: BackendType;
6
6
  schema?: dndevSchema<T>;
7
+ /** Entity definition - auto-generates schema if schema not provided */
8
+ entity?: Entity;
7
9
  /** TanStack Query stale time in ms (default: 5 min) */
8
10
  staleTime?: number;
9
11
  /** Disable caching (bypass TanStack Query) */
10
12
  noCache?: boolean;
11
13
  }
12
14
  /**
13
- * Selector type for useCrud hook
15
+ * CRUD API return type - complete interface for useCrud hook
16
+ * Consistent with CrudAPI from @donotdev/types
14
17
  */
15
- export type CrudSelector = 'isAvailable';
16
- /**
17
- * React hook for CRUD operations
18
- *
19
- * @overload Selector mode - get global CRUD state
20
- */
21
- export declare function useCrud(selector: 'isAvailable'): boolean;
22
- /**
23
- * @overload Collection mode - full CRUD operations
24
- */
25
- export declare function useCrud<T = unknown>(collection: string, options?: UseCrudOptions<T>): {
18
+ export interface UseCrudReturn<T> {
19
+ /** Feature status: 'initializing' | 'ready' | 'degraded' | 'error' */
26
20
  status: FeatureStatus;
21
+ /** Current data (from get/subscribe) */
27
22
  data: T | null;
23
+ /** Loading state for async operations */
28
24
  loading: boolean;
25
+ /** Last error encountered */
29
26
  error: Error | null;
27
+ /** Fetch single document by ID */
30
28
  get: (id: string) => Promise<T | null>;
29
+ /** Set/replace document by ID */
31
30
  set: (id: string, data: T) => Promise<void>;
31
+ /** Partial update document by ID */
32
32
  update: (id: string, data: Partial<T>) => Promise<void>;
33
+ /** Delete document by ID */
33
34
  delete: (id: string) => Promise<void>;
35
+ /** Add new document (auto-generated ID) */
34
36
  add: (data: T) => Promise<string>;
37
+ /** Query collection with filters */
35
38
  query: (options: QueryOptions) => Promise<T[]>;
39
+ /** Subscribe to document changes */
36
40
  subscribe: (id: string, callback: (data: T | null, error?: Error) => void) => () => void;
41
+ /** Subscribe to collection changes */
37
42
  subscribeToCollection: (options: QueryOptions, callback: (data: T[], error?: Error) => void) => () => void;
38
- /** Invalidate cache for this collection */
43
+ /** Invalidate cache for this collection (TanStack Query) */
39
44
  invalidate: () => Promise<void>;
45
+ /** Whether CRUD is available and operational (status === 'ready') */
40
46
  isAvailable: boolean;
41
- };
47
+ }
48
+ /**
49
+ * React hook for CRUD operations with lazy-loaded TanStack Query caching
50
+ *
51
+ * Collection-scoped hook that returns full CRUD API for a specific collection.
52
+ * Uses unified FeatureStatus enum for lifecycle management.
53
+ *
54
+ * **Usage:**
55
+ * ```typescript
56
+ * // With entity (auto-generates schema, derives collection, defaults to 'firestore' backend)
57
+ * const { status, data, get, set, query } = useCrud(carEntity);
58
+ *
59
+ * // With entity and explicit backend
60
+ * const { status, data, get, set, query } = useCrud(carEntity, { backend: 'functions' });
61
+ *
62
+ * // With collection string and entity
63
+ * const { status, data, get, set, query } = useCrud('cars', { entity: carEntity });
64
+ *
65
+ * // With explicit schema
66
+ * const { status, data, get, set, query } = useCrud('cars', { schema: CarSchema });
67
+ *
68
+ * // Check availability
69
+ * if (!isAvailable) return <Degraded />;
70
+ * if (status === 'initializing') return <Loader />;
71
+ *
72
+ * // Use CRUD operations
73
+ * const car = await get('car-123');
74
+ * await set('car-123', { make: 'Toyota', model: 'Camry' });
75
+ * ```
76
+ *
77
+ * **Status values:**
78
+ * - `initializing`: CRUD service loading
79
+ * - `ready`: Fully operational
80
+ * - `degraded`: Feature unavailable (no schema, no consent)
81
+ * - `error`: Error occurred
82
+ *
83
+ * @template T - Document type for this collection
84
+ * @param entityOrCollection - Entity definition (auto-generates schema) or collection name
85
+ * @param options - Configuration options (required if first param is collection string)
86
+ * @returns Full CRUD API for the collection
87
+ *
88
+ * @version 0.0.5
89
+ * @since 0.0.1
90
+ * @author AMBROISE PARK Consulting
91
+ */
92
+ export declare function useCrud<T = unknown>(entity: Entity, options?: UseCrudOptions<T>): UseCrudReturn<T>;
93
+ export declare function useCrud<T = unknown>(collection: string, options?: UseCrudOptions<T>): UseCrudReturn<T>;
42
94
  //# sourceMappingURL=useCrud.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCrud.d.ts","sourceRoot":"","sources":["../src/useCrud.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQjE,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAmCvB,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACxB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC;AAEzC;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC;AAE1D;;GAEG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EACjC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GAC1B;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,SAAS,EAAE,CACT,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,KAC9C,MAAM,IAAI,CAAC;IAChB,qBAAqB,EAAE,CACrB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,KACzC,MAAM,IAAI,CAAC;IAChB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC"}
1
+ {"version":3,"file":"useCrud.d.ts","sourceRoot":"","sources":["../src/useCrud.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQzE,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AAoCvB,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACxB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,sEAAsE;IACtE,MAAM,EAAE,aAAa,CAAC;IACtB,wCAAwC;IACxC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,yCAAyC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kCAAkC;IAClC,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,iCAAiC;IACjC,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,oCAAoC;IACpC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,4BAA4B;IAC5B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,2CAA2C;IAC3C,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,oCAAoC;IACpC,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/C,oCAAoC;IACpC,SAAS,EAAE,CACT,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,KAC9C,MAAM,IAAI,CAAC;IAChB,sCAAsC;IACtC,qBAAqB,EAAE,CACrB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,KACzC,MAAM,IAAI,CAAC;IAChB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EACjC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GAC1B,aAAa,CAAC,CAAC,CAAC,CAAC;AACpB,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EACjC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,GAC1B,aAAa,CAAC,CAAC,CAAC,CAAC"}
package/dist/useCrud.js CHANGED
@@ -1 +1 @@
1
- "use client";import{useEffect as N}from"react";import{DEGRADED_CRUD_API as I,FEATURE_STATUS as d,useFeatureConsent as k}from"@donotdev/core";import{FRAMEWORK_FEATURES as z,handleError as G,isClient as L}from"@donotdev/core";import{useCrudStore as c}from"./CrudStore";import{getCrudService as M}from"./CrudService";let r=null,i=null,C=null,q=!1;const K=1e3*60*5;async function U(){if(i)return i;const{QueryClient:o}=await import("@tanstack/react-query");return i=new o({defaultOptions:{queries:{staleTime:K,gcTime:1e3*60*30,retry:1,refetchOnWindowFocus:!1}}}),i}function B(o,f={}){const l=k(z.CRUD),_=c(e=>e.crudService!==null);if(o==="isAvailable")return l?_:I.isAvailable;const t=o,y=f.backend||"firestore",u=f.schema,v=f.staleTime??K,a=f.noCache??!1;N(()=>{if(!L()||!l||!u)return;const{backend:e}=c.getState();e===y&&r||C||(C=(async()=>{try{const n=M();r=n,n.setStore(c),await n.initialize(y),q=!1}catch(n){q||(G(n,{userMessage:"Failed to initialize CRUD service.",context:{backend:y,collection:t},severity:"error"}),q=!0)}finally{C=null}})())},[l,y,u]);const E=async e=>r?a?r.get(t,e,u):(await U()).fetchQuery({queryKey:["crud",t,"get",e],queryFn:()=>r.get(t,e,u),staleTime:v}):null,A=async(e,n)=>{r&&(await r.set(t,e,n,u),!a&&i&&i.invalidateQueries({queryKey:["crud",t]}))},b=async(e,n)=>{r&&(await r.update(t,e,n),!a&&i&&i.invalidateQueries({queryKey:["crud",t]}))},D=async e=>{r&&(await r.delete(t,e),!a&&i&&i.invalidateQueries({queryKey:["crud",t]}))},g=async e=>{if(!r)return"";const n=await r.add(t,e,u);return!a&&i&&i.invalidateQueries({queryKey:["crud",t]}),n},T=async e=>r?a?r.query(t,e,u):(await U()).fetchQuery({queryKey:["crud",t,"query",JSON.stringify(e)],queryFn:()=>r.query(t,e,u),staleTime:v}):[],S=(e,n)=>r?r.subscribe(t,e,(s,m)=>{!a&&i&&s&&i.setQueryData(["crud",t,"get",e],s),n(s,m)},u):()=>{},R=(e,n)=>r?r.subscribeToCollection(t,e,(s,m)=>{!a&&i&&s&&i.setQueryData(["crud",t,"query",JSON.stringify(e)],s),n(s,m)},u):()=>{},w=async()=>{i&&await i.invalidateQueries({queryKey:["crud",t]})},Q=c(e=>e.collections[t]?.data.current||null),h=c(e=>e.collections[t]?.loading||!1),F=c(e=>e.collections[t]?.error||null),p=l?r?d.READY:d.INITIALIZING:d.DEGRADED;return!l||!u||!r?{...I,status:p,data:Q,loading:h,error:F,get:E,set:A,update:b,delete:D,add:g,query:T,subscribe:S,subscribeToCollection:R,invalidate:w,isAvailable:!1}:{status:d.READY,data:Q,loading:h,error:F,get:E,set:A,update:b,delete:D,add:g,query:T,subscribe:S,subscribeToCollection:R,invalidate:w,isAvailable:!0}}export{B as useCrud};
1
+ "use client";import{useEffect as U,useMemo as _}from"react";import{DEGRADED_CRUD_API as P,FEATURE_STATUS as y,useFeatureConsent as k}from"@donotdev/core";import{FRAMEWORK_FEATURES as z,handleError as M,isClient as G}from"@donotdev/core";import{useCrudStore as l}from"./CrudStore";import{getCrudService as L}from"./CrudService";import{createEntitySchema as x}from"./forms/utils/createEntitySchema";let t=null,n=null,q=null,C=!1;const F=1e3*60*5;async function K(){if(n)return n;const{QueryClient:a}=await import("@tanstack/react-query");return n=new a({defaultOptions:{queries:{staleTime:F,gcTime:1e3*60*30,retry:1,refetchOnWindowFocus:!1}}}),n}function Z(a,s={}){const f=k(z.CRUD),m=typeof a=="object"?a:s.entity,r=typeof a=="string"?a:a.collection,d=s.backend||"firestore",D=s.staleTime??F,c=s.noCache??!1,u=_(()=>{if(s.schema)return s.schema;if(m)return x(m,"full")},[s.schema,m]);U(()=>{if(!G()||!f||!u)return;const{backend:e}=l.getState();e===d&&t||q||(q=(async()=>{try{const i=L();t=i,i.setStore(l),await i.initialize(d),C=!1}catch(i){C||(M(i,{userMessage:"Failed to initialize CRUD service.",context:{backend:d,collection:r},severity:"error"}),C=!0)}finally{q=null}})())},[f,d,u,r]);const g=async e=>t?c?t.get(r,e,u):(await K()).fetchQuery({queryKey:["crud",r,"get",e],queryFn:()=>t.get(r,e,u),staleTime:D}):null,v=async(e,i)=>{t&&(await t.set(r,e,i,u),!c&&n&&n.invalidateQueries({queryKey:["crud",r]}))},b=async(e,i)=>{t&&(await t.update(r,e,i),!c&&n&&n.invalidateQueries({queryKey:["crud",r]}))},h=async e=>{t&&(await t.delete(r,e),!c&&n&&n.invalidateQueries({queryKey:["crud",r]}))},A=async e=>{if(!t)return"";const i=await t.add(r,e,u);return!c&&n&&n.invalidateQueries({queryKey:["crud",r]}),i},T=async e=>t?c?t.query(r,e,u):(await K()).fetchQuery({queryKey:["crud",r,"query",JSON.stringify(e)],queryFn:()=>t.query(r,e,u),staleTime:D}):[],w=(e,i)=>t?t.subscribe(r,e,(o,E)=>{!c&&n&&o&&n.setQueryData(["crud",r,"get",e],o),i(o,E)},u):()=>{},S=(e,i)=>t?t.subscribeToCollection(r,e,(o,E)=>{!c&&n&&o&&n.setQueryData(["crud",r,"query",JSON.stringify(e)],o),i(o,E)},u):()=>{},R=async()=>{n&&await n.invalidateQueries({queryKey:["crud",r]})},Q=l(e=>e.collections[r]?.data.current||null),I=l(e=>e.collections[r]?.loading||!1),p=l(e=>e.collections[r]?.error||null),N=f?t?y.READY:y.INITIALIZING:y.DEGRADED;return!f||!u||!t?{...P,status:N,data:Q,loading:I,error:p,get:g,set:v,update:b,delete:h,add:A,query:T,subscribe:w,subscribeToCollection:S,invalidate:R,isAvailable:!1}:{status:y.READY,data:Q,loading:I,error:p,get:g,set:v,update:b,delete:h,add:A,query:T,subscribe:w,subscribeToCollection:S,invalidate:R,isAvailable:!0}}export{Z as useCrud};
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @fileoverview Image Processing Utilities
3
+ * @description Client-side image processing for WebP conversion, resizing, and thumbnail generation
4
+ *
5
+ * @version 0.0.1
6
+ * @since 0.0.1
7
+ * @author AMBROISE PARK Consulting
8
+ */
9
+ export interface ProcessedImage {
10
+ fullBlob: Blob;
11
+ thumbBlob: Blob;
12
+ width: number;
13
+ height: number;
14
+ }
15
+ export interface ProcessImageOptions {
16
+ /** Maximum width for full-size image (default: 1920) */
17
+ maxWidth?: number;
18
+ /** Maximum height for full-size image (default: 1440) */
19
+ maxHeight?: number;
20
+ /** Thumbnail width (default: 300) */
21
+ thumbWidth?: number;
22
+ /** Thumbnail height (default: 225) */
23
+ thumbHeight?: number;
24
+ /** Target aspect ratio (default: 4/3) */
25
+ aspectRatio?: number;
26
+ /** WebP quality (0-1, default: 0.9 for full, 0.8 for thumb) */
27
+ quality?: number;
28
+ /** Add transparent background for non-matching aspect ratios */
29
+ transparentBackground?: boolean;
30
+ /** Crop region (if provided, overrides automatic center crop) */
31
+ crop?: {
32
+ x: number;
33
+ y: number;
34
+ width: number;
35
+ height: number;
36
+ };
37
+ }
38
+ /**
39
+ * Resize and convert image to WebP with 4:3 aspect ratio
40
+ */
41
+ export declare function processImage(file: File, options?: ProcessImageOptions): Promise<ProcessedImage>;
42
+ /**
43
+ * Validate image file
44
+ */
45
+ export declare function validateImageFile(file: File, maxSizeBytes?: number): {
46
+ valid: boolean;
47
+ error?: string;
48
+ };
49
+ //# sourceMappingURL=imageProcessing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imageProcessing.d.ts","sourceRoot":"","sources":["../../src/utils/imageProcessing.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iEAAiE;IACjE,IAAI,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAChE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,cAAc,CAAC,CAsEzB;AAwHD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,EACV,YAAY,CAAC,EAAE,MAAM,GACpB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAgBpC"}
@@ -0,0 +1 @@
1
+ async function x(t,r={}){const{maxWidth:o=1920,maxHeight:a=1440,thumbWidth:d=300,thumbHeight:i=225,aspectRatio:e=4/3,quality:h=.9,transparentBackground:c=!0,crop:l}=r;return new Promise((f,s)=>{const n=new Image,u=new FileReader;u.onload=w=>{n.src=w.target?.result},u.onerror=()=>s(new Error("Failed to read file")),n.onload=async()=>{try{const{width:w,height:F}=g(l?l.width:n.width,l?l.height:n.height,o,a,e),m=await b(n,w,F,e,h,c,l),v=await b(n,d,i,e,.8,c,l);f({fullBlob:m,thumbBlob:v,width:w,height:F})}catch(w){s(w)}},n.onerror=()=>s(new Error("Failed to load image")),u.readAsDataURL(t)})}function g(t,r,o,a,d){let i=t,e=r;i>o&&(e=o/i*e,i=o),e>a&&(i=a/e*i,e=a);const h=i/e;return Math.abs(h-d)>.01&&(h>d?e=i/d:i=e*d),{width:Math.round(i),height:Math.round(e)}}async function b(t,r,o,a,d,i,e){const h=document.createElement("canvas"),c=h.getContext("2d");if(!c)throw new Error("Failed to get canvas context");h.width=r,h.height=o,i?c.clearRect(0,0,r,o):(c.fillStyle="#FFFFFF",c.fillRect(0,0,r,o));let l,f,s,n;if(e)l=e.x,f=e.y,s=e.width,n=e.height;else{const u=t.width/t.height;s=t.width,n=t.height,l=0,f=0,u>a?(s=t.height*a,l=(t.width-s)/2):u<a&&(n=t.width/a,f=(t.height-n)/2)}return c.drawImage(t,l,f,s,n,0,0,r,o),new Promise((u,w)=>{h.toBlob(F=>{F?u(F):w(new Error("Failed to convert canvas to blob"))},"image/webp",d)})}function y(t,r){return t.type.startsWith("image/")?r&&t.size>r?{valid:!1,error:`File size exceeds ${(r/1048576).toFixed(1)}MB limit`}:{valid:!0}:{valid:!1,error:"File must be an image"}}export{x as processImage,y as validateImageFile};
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @fileoverview Image Storage Utilities
3
+ * @description Handle image uploads to Firebase Storage with progress tracking, WebP conversion, and thumbnails
4
+ * Uses @donotdev/firebase for storage operations
5
+ *
6
+ * @version 0.0.2
7
+ * @since 0.0.1
8
+ * @author AMBROISE PARK Consulting
9
+ */
10
+ import { type UploadProgressCallback } from '@donotdev/firebase';
11
+ import type { Picture } from '@donotdev/types';
12
+ export type { Picture };
13
+ export interface UploadProgress {
14
+ bytesTransferred: number;
15
+ totalBytes: number;
16
+ progress: number;
17
+ }
18
+ export interface UploadImageOptions {
19
+ /** Storage path (default: 'uploads/images') */
20
+ storagePath?: string;
21
+ /** Custom filename (default: timestamp_originalname) */
22
+ filename?: string;
23
+ /** Progress callback */
24
+ onProgress?: UploadProgressCallback;
25
+ }
26
+ /**
27
+ * Upload full and thumbnail images to Firebase Storage with progress tracking
28
+ * Uses @donotdev/firebase uploadFileResumable for progress callbacks
29
+ */
30
+ export declare function uploadImage(fullBlob: Blob, thumbBlob: Blob, originalFilename: string, options?: UploadImageOptions): Promise<Picture>;
31
+ /**
32
+ * Delete image from Firebase Storage using @donotdev/firebase utilities
33
+ */
34
+ export declare function deleteImage(picture: Picture): Promise<void>;
35
+ //# sourceMappingURL=imageStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imageStorage.d.ts","sourceRoot":"","sources":["../../src/utils/imageStorage.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,YAAY,EAAE,OAAO,EAAE,CAAC;AAExB,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,UAAU,CAAC,EAAE,sBAAsB,CAAC;CACrC;AAYD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,IAAI,EACd,SAAS,EAAE,IAAI,EACf,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,OAAO,CAAC,CAmFlB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjE"}
@@ -0,0 +1 @@
1
+ import{uploadFileResumable as c,deleteFileByUrl as i,getFileUrl as m}from"@donotdev/firebase";import{handleError as _}from"@donotdev/core";function F(e){return e.replace(/[^a-zA-Z0-9.-]/g,"_").replace(/_{2,}/g,"_").toLowerCase()}async function N(e,l,b,h={}){const{storagePath:r="uploads/images",filename:f,onProgress:s}=h,p=Date.now(),t=(f||`${p}_${F(b)}`).replace(/\.[^/.]+$/,""),w=`${r}/${t}_full.webp`,g=`${r}/${t}_thumb.webp`;try{const u=s?a=>{s({bytesTransferred:a.bytesTransferred,totalBytes:a.totalBytes*2,progress:a.progress*.5})}:void 0,o=new File([e],`${t}_full.webp`,{type:"image/webp"}),{promise:n}=c(o,{basePath:r,filename:`${t}_full.webp`,onProgress:u,metadata:{contentType:"image/webp"}}),d=(await n).url,y=s?a=>{s({bytesTransferred:a.bytesTransferred+e.size,totalBytes:e.size+l.size,progress:50+a.progress*.5})}:void 0,P=new File([l],`${t}_thumb.webp`,{type:"image/webp"}),{promise:U}=c(P,{basePath:r,filename:`${t}_thumb.webp`,onProgress:y,metadata:{contentType:"image/webp"}}),$=(await U).url;return{fullUrl:d,thumbUrl:$}}catch(u){try{const o=await m(w).catch(()=>null),n=await m(g).catch(()=>null);o&&await i(o).catch(()=>{}),n&&await i(n).catch(()=>{})}catch{}throw u}}async function k(e){try{await Promise.all([i(e.fullUrl),i(e.thumbUrl)])}catch(l){throw _(l,{userMessage:"Failed to delete image",severity:"error",context:{fullUrl:e.fullUrl,thumbUrl:e.thumbUrl}}),l}}export{k as deleteImage,N as uploadImage};
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @fileoverview Image Utility Functions
3
+ * @description Hash generation, FLIP rotation, deduplication, and local preview management
4
+ *
5
+ * @version 0.0.1
6
+ * @since 0.0.1
7
+ * @author AMBROISE PARK Consulting
8
+ */
9
+ import type { Picture } from '@donotdev/types';
10
+ /**
11
+ * Generate SHA-256 hash of file for deduplication
12
+ */
13
+ export declare function generateFileHash(file: File): Promise<string>;
14
+ /**
15
+ * Create local preview URL from File
16
+ */
17
+ export declare function createPreviewURL(file: File): string;
18
+ /**
19
+ * Cleanup preview URL to prevent memory leaks
20
+ */
21
+ export declare function revokePreviewURL(url: string): void;
22
+ /**
23
+ * Rotate image by 90 degrees clockwise
24
+ */
25
+ export declare function rotateImage90(file: File): Promise<File>;
26
+ /**
27
+ * Image metadata for local state management
28
+ */
29
+ export interface ImageMetadata {
30
+ /** Unique ID for this image instance */
31
+ id: string;
32
+ /** Original or rotated File object */
33
+ file: File;
34
+ /** Local preview URL (blob:...) */
35
+ previewURL: string;
36
+ /** SHA-256 hash for deduplication */
37
+ hash: string;
38
+ /** Number of 90° rotations applied (0-3) */
39
+ rotation: number;
40
+ /** Upload progress (0-100), null if not uploading */
41
+ uploadProgress: number | null;
42
+ /** Uploaded Picture URLs, null if not uploaded */
43
+ uploaded: Picture | null;
44
+ /** Error message if upload failed */
45
+ error: string | null;
46
+ }
47
+ /**
48
+ * Action for undo/redo stack
49
+ */
50
+ export type ImageAction = {
51
+ type: 'add';
52
+ images: ImageMetadata[];
53
+ } | {
54
+ type: 'remove';
55
+ indices: number[];
56
+ } | {
57
+ type: 'reorder';
58
+ from: number;
59
+ to: number;
60
+ } | {
61
+ type: 'rotate';
62
+ index: number;
63
+ };
64
+ /**
65
+ * Undo/redo stack manager
66
+ */
67
+ export declare class UndoRedoManager {
68
+ private undoStack;
69
+ private redoStack;
70
+ private maxStackSize;
71
+ push(action: ImageAction): void;
72
+ undo(): ImageAction | null;
73
+ redo(): ImageAction | null;
74
+ canUndo(): boolean;
75
+ canRedo(): boolean;
76
+ clear(): void;
77
+ }
78
+ /**
79
+ * Check for duplicate files by hash (within current set)
80
+ */
81
+ export declare function findDuplicatesByHash(images: ImageMetadata[], newHash: string): ImageMetadata[];
82
+ /**
83
+ * Generate unique ID for image
84
+ */
85
+ export declare function generateImageId(): string;
86
+ //# sourceMappingURL=imageUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imageUtils.d.ts","sourceRoot":"","sources":["../../src/utils/imageUtils.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAKlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAyD7D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,IAAI,EAAE,IAAI,CAAC;IACX,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kDAAkD;IAClD,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,qCAAqC;IACrC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,YAAY,CAAM;IAE1B,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAS/B,IAAI,IAAI,WAAW,GAAG,IAAI;IAS1B,IAAI,IAAI,WAAW,GAAG,IAAI;IAS1B,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,OAAO;IAIlB,KAAK,IAAI,IAAI;CAId;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,EAAE,MAAM,GACd,aAAa,EAAE,CAEjB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1 @@
1
+ async function d(e){const t=await e.arrayBuffer(),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(o=>o.toString(16).padStart(2,"0")).join("")}function h(e){return URL.createObjectURL(e)}function u(e){e.startsWith("blob:")&&URL.revokeObjectURL(e)}async function l(e){return new Promise((t,r)=>{const a=new Image,o=new FileReader;o.onload=n=>{if(!n.target?.result){r(new Error("Failed to read file"));return}a.src=n.target.result},o.onerror=()=>r(new Error("Failed to read file")),a.onload=()=>{const n=document.createElement("canvas"),i=n.getContext("2d");if(!i){r(new Error("Failed to get canvas context"));return}n.width=a.height,n.height=a.width,i.translate(n.width/2,n.height/2),i.rotate(Math.PI/2),i.drawImage(a,-a.width/2,-a.height/2),n.toBlob(s=>{if(s){const c=new File([s],e.name,{type:e.type,lastModified:Date.now()});t(c)}else r(new Error("Failed to create blob from canvas"))},e.type,.95)},a.onerror=()=>r(new Error("Failed to load image")),o.readAsDataURL(e)})}class f{undoStack=[];redoStack=[];maxStackSize=50;push(t){this.undoStack.push(t),this.undoStack.length>this.maxStackSize&&this.undoStack.shift(),this.redoStack=[]}undo(){const t=this.undoStack.pop();return t?(this.redoStack.push(t),t):null}redo(){const t=this.redoStack.pop();return t?(this.undoStack.push(t),t):null}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}clear(){this.undoStack=[],this.redoStack=[]}}function g(e,t){return e.filter(r=>r.hash===t)}function p(){return`img_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}export{f as UndoRedoManager,h as createPreviewURL,g as findDuplicatesByHash,d as generateFileHash,p as generateImageId,u as revokePreviewURL,l as rotateImage90};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donotdev/crud",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -14,7 +14,9 @@
14
14
  "default": "./dist/index.js"
15
15
  }
16
16
  },
17
- "sideEffects": false,
17
+ "sideEffects": [
18
+ "./src/builtinFieldTypes.tsx"
19
+ ],
18
20
  "files": [
19
21
  "dist",
20
22
  "package.json",
@@ -47,17 +49,18 @@
47
49
  "type-check": "tsc --noEmit"
48
50
  },
49
51
  "dependencies": {
50
- "@donotdev/components": "0.0.4",
51
- "@donotdev/core": "0.0.4"
52
+ "@donotdev/components": "^0.0.12",
53
+ "@donotdev/core": "^0.0.13",
54
+ "@hookform/resolvers": "^5.2.2",
55
+ "react-easy-crop": "^5.5.6"
52
56
  },
53
57
  "peerDependencies": {
54
- "@donotdev/firebase": "0.0.4",
55
- "@hookform/resolvers": "^5.2.2",
58
+ "@donotdev/firebase": "^0.0.5",
56
59
  "firebase": "^12.5.0",
57
60
  "lucide-react": "^0.562.0",
58
61
  "react": "^19.2.3",
59
62
  "react-dom": "^19.2.3",
60
- "react-hook-form": "^7.68.0",
63
+ "react-hook-form": "^7.71.0",
61
64
  "valibot": "^1.2.0"
62
65
  },
63
66
  "peerDependenciesMeta": {}