@apvee/spfx-react-toolkit 1.0.0

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 (220) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2012 -0
  3. package/lib/core/atoms.internal.d.ts +53 -0
  4. package/lib/core/atoms.internal.d.ts.map +1 -0
  5. package/lib/core/atoms.internal.js +35 -0
  6. package/lib/core/atoms.internal.js.map +1 -0
  7. package/lib/core/context.internal.d.ts +23 -0
  8. package/lib/core/context.internal.d.ts.map +1 -0
  9. package/lib/core/context.internal.js +34 -0
  10. package/lib/core/context.internal.js.map +1 -0
  11. package/lib/core/index.d.ts +6 -0
  12. package/lib/core/index.d.ts.map +1 -0
  13. package/lib/core/index.js +6 -0
  14. package/lib/core/index.js.map +1 -0
  15. package/lib/core/provider-application-customizer.d.ts +57 -0
  16. package/lib/core/provider-application-customizer.d.ts.map +1 -0
  17. package/lib/core/provider-application-customizer.js +45 -0
  18. package/lib/core/provider-application-customizer.js.map +1 -0
  19. package/lib/core/provider-base.internal.d.ts +20 -0
  20. package/lib/core/provider-base.internal.d.ts.map +1 -0
  21. package/lib/core/provider-base.internal.js +126 -0
  22. package/lib/core/provider-base.internal.js.map +1 -0
  23. package/lib/core/provider-field-customizer.d.ts +58 -0
  24. package/lib/core/provider-field-customizer.d.ts.map +1 -0
  25. package/lib/core/provider-field-customizer.js +46 -0
  26. package/lib/core/provider-field-customizer.js.map +1 -0
  27. package/lib/core/provider-listview-commandset.d.ts +60 -0
  28. package/lib/core/provider-listview-commandset.d.ts.map +1 -0
  29. package/lib/core/provider-listview-commandset.js +48 -0
  30. package/lib/core/provider-listview-commandset.js.map +1 -0
  31. package/lib/core/provider-webpart.d.ts +48 -0
  32. package/lib/core/provider-webpart.d.ts.map +1 -0
  33. package/lib/core/provider-webpart.js +36 -0
  34. package/lib/core/provider-webpart.js.map +1 -0
  35. package/lib/core/types.d.ts +84 -0
  36. package/lib/core/types.d.ts.map +1 -0
  37. package/lib/core/types.js +4 -0
  38. package/lib/core/types.js.map +1 -0
  39. package/lib/hooks/index.d.ts +34 -0
  40. package/lib/hooks/index.d.ts.map +1 -0
  41. package/lib/hooks/index.js +34 -0
  42. package/lib/hooks/index.js.map +1 -0
  43. package/lib/hooks/useSPFxAadHttpClient.d.ts +231 -0
  44. package/lib/hooks/useSPFxAadHttpClient.d.ts.map +1 -0
  45. package/lib/hooks/useSPFxAadHttpClient.js +299 -0
  46. package/lib/hooks/useSPFxAadHttpClient.js.map +1 -0
  47. package/lib/hooks/useSPFxContainerInfo.d.ts +41 -0
  48. package/lib/hooks/useSPFxContainerInfo.d.ts.map +1 -0
  49. package/lib/hooks/useSPFxContainerInfo.js +47 -0
  50. package/lib/hooks/useSPFxContainerInfo.js.map +1 -0
  51. package/lib/hooks/useSPFxContainerSize.d.ts +119 -0
  52. package/lib/hooks/useSPFxContainerSize.d.ts.map +1 -0
  53. package/lib/hooks/useSPFxContainerSize.js +150 -0
  54. package/lib/hooks/useSPFxContainerSize.js.map +1 -0
  55. package/lib/hooks/useSPFxContext.d.ts +14 -0
  56. package/lib/hooks/useSPFxContext.d.ts.map +1 -0
  57. package/lib/hooks/useSPFxContext.js +16 -0
  58. package/lib/hooks/useSPFxContext.js.map +1 -0
  59. package/lib/hooks/useSPFxCorrelationInfo.d.ts +51 -0
  60. package/lib/hooks/useSPFxCorrelationInfo.d.ts.map +1 -0
  61. package/lib/hooks/useSPFxCorrelationInfo.js +58 -0
  62. package/lib/hooks/useSPFxCorrelationInfo.js.map +1 -0
  63. package/lib/hooks/useSPFxCrossSitePermissions.d.ts +81 -0
  64. package/lib/hooks/useSPFxCrossSitePermissions.d.ts.map +1 -0
  65. package/lib/hooks/useSPFxCrossSitePermissions.js +132 -0
  66. package/lib/hooks/useSPFxCrossSitePermissions.js.map +1 -0
  67. package/lib/hooks/useSPFxDisplayMode.d.ts +61 -0
  68. package/lib/hooks/useSPFxDisplayMode.d.ts.map +1 -0
  69. package/lib/hooks/useSPFxDisplayMode.js +69 -0
  70. package/lib/hooks/useSPFxDisplayMode.js.map +1 -0
  71. package/lib/hooks/useSPFxEnvironmentInfo.d.ts +63 -0
  72. package/lib/hooks/useSPFxEnvironmentInfo.d.ts.map +1 -0
  73. package/lib/hooks/useSPFxEnvironmentInfo.js +91 -0
  74. package/lib/hooks/useSPFxEnvironmentInfo.js.map +1 -0
  75. package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts +105 -0
  76. package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts.map +1 -0
  77. package/lib/hooks/useSPFxFluent9ThemeInfo.js +136 -0
  78. package/lib/hooks/useSPFxFluent9ThemeInfo.js.map +1 -0
  79. package/lib/hooks/useSPFxHubSiteInfo.d.ts +80 -0
  80. package/lib/hooks/useSPFxHubSiteInfo.d.ts.map +1 -0
  81. package/lib/hooks/useSPFxHubSiteInfo.js +127 -0
  82. package/lib/hooks/useSPFxHubSiteInfo.js.map +1 -0
  83. package/lib/hooks/useSPFxInstanceInfo.d.ts +41 -0
  84. package/lib/hooks/useSPFxInstanceInfo.d.ts.map +1 -0
  85. package/lib/hooks/useSPFxInstanceInfo.js +40 -0
  86. package/lib/hooks/useSPFxInstanceInfo.js.map +1 -0
  87. package/lib/hooks/useSPFxListInfo.d.ts +64 -0
  88. package/lib/hooks/useSPFxListInfo.d.ts.map +1 -0
  89. package/lib/hooks/useSPFxListInfo.js +70 -0
  90. package/lib/hooks/useSPFxListInfo.js.map +1 -0
  91. package/lib/hooks/useSPFxLocaleInfo.d.ts +123 -0
  92. package/lib/hooks/useSPFxLocaleInfo.d.ts.map +1 -0
  93. package/lib/hooks/useSPFxLocaleInfo.js +109 -0
  94. package/lib/hooks/useSPFxLocaleInfo.js.map +1 -0
  95. package/lib/hooks/useSPFxLogger.d.ts +108 -0
  96. package/lib/hooks/useSPFxLogger.d.ts.map +1 -0
  97. package/lib/hooks/useSPFxLogger.js +117 -0
  98. package/lib/hooks/useSPFxLogger.js.map +1 -0
  99. package/lib/hooks/useSPFxMSGraphClient.d.ts +200 -0
  100. package/lib/hooks/useSPFxMSGraphClient.d.ts.map +1 -0
  101. package/lib/hooks/useSPFxMSGraphClient.js +264 -0
  102. package/lib/hooks/useSPFxMSGraphClient.js.map +1 -0
  103. package/lib/hooks/useSPFxOneDriveAppData.d.ts +264 -0
  104. package/lib/hooks/useSPFxOneDriveAppData.d.ts.map +1 -0
  105. package/lib/hooks/useSPFxOneDriveAppData.js +395 -0
  106. package/lib/hooks/useSPFxOneDriveAppData.js.map +1 -0
  107. package/lib/hooks/useSPFxPageContext.d.ts +37 -0
  108. package/lib/hooks/useSPFxPageContext.d.ts.map +1 -0
  109. package/lib/hooks/useSPFxPageContext.js +49 -0
  110. package/lib/hooks/useSPFxPageContext.js.map +1 -0
  111. package/lib/hooks/useSPFxPageType.d.ts +82 -0
  112. package/lib/hooks/useSPFxPageType.d.ts.map +1 -0
  113. package/lib/hooks/useSPFxPageType.js +137 -0
  114. package/lib/hooks/useSPFxPageType.js.map +1 -0
  115. package/lib/hooks/useSPFxPerformance.d.ts +72 -0
  116. package/lib/hooks/useSPFxPerformance.d.ts.map +1 -0
  117. package/lib/hooks/useSPFxPerformance.js +167 -0
  118. package/lib/hooks/useSPFxPerformance.js.map +1 -0
  119. package/lib/hooks/useSPFxPermissions.d.ts +61 -0
  120. package/lib/hooks/useSPFxPermissions.d.ts.map +1 -0
  121. package/lib/hooks/useSPFxPermissions.js +73 -0
  122. package/lib/hooks/useSPFxPermissions.js.map +1 -0
  123. package/lib/hooks/useSPFxPnP.d.ts +539 -0
  124. package/lib/hooks/useSPFxPnP.d.ts.map +1 -0
  125. package/lib/hooks/useSPFxPnP.js +533 -0
  126. package/lib/hooks/useSPFxPnP.js.map +1 -0
  127. package/lib/hooks/useSPFxPnPContext.d.ts +290 -0
  128. package/lib/hooks/useSPFxPnPContext.d.ts.map +1 -0
  129. package/lib/hooks/useSPFxPnPContext.js +340 -0
  130. package/lib/hooks/useSPFxPnPContext.js.map +1 -0
  131. package/lib/hooks/useSPFxPnPList.d.ts +545 -0
  132. package/lib/hooks/useSPFxPnPList.d.ts.map +1 -0
  133. package/lib/hooks/useSPFxPnPList.js +906 -0
  134. package/lib/hooks/useSPFxPnPList.js.map +1 -0
  135. package/lib/hooks/useSPFxPnPSearch.d.ts +540 -0
  136. package/lib/hooks/useSPFxPnPSearch.d.ts.map +1 -0
  137. package/lib/hooks/useSPFxPnPSearch.js +672 -0
  138. package/lib/hooks/useSPFxPnPSearch.js.map +1 -0
  139. package/lib/hooks/useSPFxProperties.d.ts +80 -0
  140. package/lib/hooks/useSPFxProperties.d.ts.map +1 -0
  141. package/lib/hooks/useSPFxProperties.js +95 -0
  142. package/lib/hooks/useSPFxProperties.js.map +1 -0
  143. package/lib/hooks/useSPFxSPHttpClient.d.ts +218 -0
  144. package/lib/hooks/useSPFxSPHttpClient.d.ts.map +1 -0
  145. package/lib/hooks/useSPFxSPHttpClient.js +287 -0
  146. package/lib/hooks/useSPFxSPHttpClient.js.map +1 -0
  147. package/lib/hooks/useSPFxServiceScope.d.ts +107 -0
  148. package/lib/hooks/useSPFxServiceScope.d.ts.map +1 -0
  149. package/lib/hooks/useSPFxServiceScope.js +105 -0
  150. package/lib/hooks/useSPFxServiceScope.js.map +1 -0
  151. package/lib/hooks/useSPFxSiteInfo.d.ts +116 -0
  152. package/lib/hooks/useSPFxSiteInfo.d.ts.map +1 -0
  153. package/lib/hooks/useSPFxSiteInfo.js +109 -0
  154. package/lib/hooks/useSPFxSiteInfo.js.map +1 -0
  155. package/lib/hooks/useSPFxStorage.d.ts +81 -0
  156. package/lib/hooks/useSPFxStorage.d.ts.map +1 -0
  157. package/lib/hooks/useSPFxStorage.js +140 -0
  158. package/lib/hooks/useSPFxStorage.js.map +1 -0
  159. package/lib/hooks/useSPFxTeams.d.ts +63 -0
  160. package/lib/hooks/useSPFxTeams.d.ts.map +1 -0
  161. package/lib/hooks/useSPFxTeams.js +198 -0
  162. package/lib/hooks/useSPFxTeams.js.map +1 -0
  163. package/lib/hooks/useSPFxTenantProperty.d.ts +389 -0
  164. package/lib/hooks/useSPFxTenantProperty.d.ts.map +1 -0
  165. package/lib/hooks/useSPFxTenantProperty.js +683 -0
  166. package/lib/hooks/useSPFxTenantProperty.js.map +1 -0
  167. package/lib/hooks/useSPFxThemeInfo.d.ts +27 -0
  168. package/lib/hooks/useSPFxThemeInfo.d.ts.map +1 -0
  169. package/lib/hooks/useSPFxThemeInfo.js +33 -0
  170. package/lib/hooks/useSPFxThemeInfo.js.map +1 -0
  171. package/lib/hooks/useSPFxUserInfo.d.ts +47 -0
  172. package/lib/hooks/useSPFxUserInfo.d.ts.map +1 -0
  173. package/lib/hooks/useSPFxUserInfo.js +47 -0
  174. package/lib/hooks/useSPFxUserInfo.js.map +1 -0
  175. package/lib/hooks/useSPFxUserPhoto.d.ts +270 -0
  176. package/lib/hooks/useSPFxUserPhoto.d.ts.map +1 -0
  177. package/lib/hooks/useSPFxUserPhoto.js +346 -0
  178. package/lib/hooks/useSPFxUserPhoto.js.map +1 -0
  179. package/lib/index.d.ts +3 -0
  180. package/lib/index.d.ts.map +1 -0
  181. package/lib/index.js +3 -0
  182. package/lib/index.js.map +1 -0
  183. package/lib/utils/index.d.ts +1 -0
  184. package/lib/utils/index.d.ts.map +1 -0
  185. package/lib/utils/index.js +3 -0
  186. package/lib/utils/index.js.map +1 -0
  187. package/lib/utils/resize-observer.internal.d.ts +10 -0
  188. package/lib/utils/resize-observer.internal.d.ts.map +1 -0
  189. package/lib/utils/resize-observer.internal.js +34 -0
  190. package/lib/utils/resize-observer.internal.js.map +1 -0
  191. package/lib/utils/theme-subscription.internal.d.ts +11 -0
  192. package/lib/utils/theme-subscription.internal.d.ts.map +1 -0
  193. package/lib/utils/theme-subscription.internal.js +58 -0
  194. package/lib/utils/theme-subscription.internal.js.map +1 -0
  195. package/lib/utils/type-guards.internal.d.ts +35 -0
  196. package/lib/utils/type-guards.internal.d.ts.map +1 -0
  197. package/lib/utils/type-guards.internal.js +88 -0
  198. package/lib/utils/type-guards.internal.js.map +1 -0
  199. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts +13 -0
  200. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts.map +1 -0
  201. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js +67 -0
  202. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js.map +1 -0
  203. package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.manifest.json +21 -0
  204. package/lib/webparts/spFxReactToolkitTest/assets/welcome-dark.png +0 -0
  205. package/lib/webparts/spFxReactToolkitTest/assets/welcome-light.png +0 -0
  206. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts +8 -0
  207. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts.map +1 -0
  208. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js +2 -0
  209. package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js.map +1 -0
  210. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts +8 -0
  211. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts.map +1 -0
  212. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js +1351 -0
  213. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js.map +1 -0
  214. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.css +2 -0
  215. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts +18 -0
  216. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts.map +1 -0
  217. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js +19 -0
  218. package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js.map +1 -0
  219. package/lib/webparts/spFxReactToolkitTest/loc/en-us.js +16 -0
  220. package/package.json +95 -0
@@ -0,0 +1,906 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { useState, useEffect, useCallback, useRef } from 'react';
38
+ import { useSPFxPnPContext } from './useSPFxPnPContext';
39
+ /**
40
+ * Hook for working with SharePoint lists using PnPjs fluent API.
41
+ * Provides query execution with automatic .top() detection, CRUD operations, pagination, and state management.
42
+ *
43
+ * **Key Features**:
44
+ * - ✅ Native PnPjs fluent API - full type-safe query building
45
+ * - ✅ Smart .top() detection - no conflicts between user .top() and pageSize
46
+ * - ✅ CRUD operations (create, read, update, delete)
47
+ * - ✅ Batch operations for bulk updates
48
+ * - ✅ Pagination with `loadMore()` and `hasMore`
49
+ * - ✅ Automatic refetch after CRUD operations
50
+ * - ✅ Local state management per component instance
51
+ * - ✅ Cross-site support via PnPContextInfo
52
+ * - ✅ ES5 compatibility (IE11 support)
53
+ *
54
+ * **How .top() Detection Works**:
55
+ * The hook uses a recursive Proxy to detect if `.top()` is called in your queryBuilder:
56
+ * - If `.top()` is specified → uses that value
57
+ * - If no `.top()` but `pageSize` option → adds `.top(pageSize)` automatically
58
+ * - If neither → no limit (SharePoint default ~100-5000)
59
+ * - If both → `.top()` wins, warning logged
60
+ *
61
+ * @template T - The type of the list item (default: unknown)
62
+ * @param listTitle - The title of the SharePoint list
63
+ * @param options - Optional configuration (pageSize for pagination)
64
+ * @param pnpContext - Optional PnP context for cross-site scenarios
65
+ * @returns Object containing query method, items, loading states, error, and CRUD operations
66
+ *
67
+ * @example Basic usage with pageSize
68
+ * ```tsx
69
+ * import { useSPFxPnPList } from '@apvee/spfx-react-toolkit';
70
+ *
71
+ * function TaskList() {
72
+ * const { query, items, loading, error } = useSPFxPnPList('Tasks', { pageSize: 50 });
73
+ *
74
+ * useEffect(() => {
75
+ * query(q =>
76
+ * q.select('Id', 'Title', 'Status', 'Priority')
77
+ * .filter("Status eq 'Active'")
78
+ * .orderBy('Priority', false)
79
+ * );
80
+ * }, [query]);
81
+ *
82
+ * if (loading) return <Spinner />;
83
+ * if (error) return <MessageBar>Error: {error.message}</MessageBar>;
84
+ *
85
+ * return (
86
+ * <ul>
87
+ * {items.map(task => (
88
+ * <li key={task.Id}>{task.Title} - {task.Status}</li>
89
+ * ))}
90
+ * </ul>
91
+ * );
92
+ * }
93
+ * ```
94
+ *
95
+ * @example Type-safe fluent filter
96
+ * ```tsx
97
+ * interface Task {
98
+ * Id: number;
99
+ * Title: string;
100
+ * Status: string;
101
+ * Priority: number;
102
+ * DueDate: string;
103
+ * }
104
+ *
105
+ * function ActiveHighPriorityTasks() {
106
+ * const { query, items, loading } = useSPFxPnPList<Task>('Tasks', { pageSize: 50 });
107
+ *
108
+ * useEffect(() => {
109
+ * query(q =>
110
+ * q.select('Id', 'Title', 'Priority', 'DueDate')
111
+ * .filter(f => f.text("Status").equals("Active")
112
+ * .and()
113
+ * .number("Priority").greaterThan(3))
114
+ * .orderBy('DueDate', true)
115
+ * );
116
+ * }, [query]);
117
+ *
118
+ * return (
119
+ * <div>
120
+ * {items.map(task => (
121
+ * <TaskCard key={task.Id} task={task} />
122
+ * ))}
123
+ * </div>
124
+ * );
125
+ * }
126
+ * ```
127
+ *
128
+ * @example Query with explicit .top()
129
+ * ```tsx
130
+ * const { query, items } = useSPFxPnPList<Task>('Tasks');
131
+ *
132
+ * useEffect(() => {
133
+ * // User specifies .top() explicitly - takes precedence
134
+ * query(q =>
135
+ * q.select('Id', 'Title')
136
+ * .top(100) // Hook detects this and uses it
137
+ * .orderBy('Created', false)
138
+ * );
139
+ * }, [query]);
140
+ * ```
141
+ *
142
+ * @example CRUD operations
143
+ * ```tsx
144
+ * function TaskManager() {
145
+ * const { items, create, update, remove, loading } = useSPFxPnPList<Task>('Tasks');
146
+ *
147
+ * const handleCreate = async () => {
148
+ * try {
149
+ * const newId = await create({
150
+ * Title: 'New Task',
151
+ * Status: 'Active',
152
+ * Priority: 3
153
+ * });
154
+ * console.log('Created task with ID:', newId);
155
+ * // List automatically refetches
156
+ * } catch (error) {
157
+ * console.error('Create failed:', error);
158
+ * }
159
+ * };
160
+ *
161
+ * const handleUpdate = async (id: number) => {
162
+ * await update(id, { Status: 'Completed' });
163
+ * // List automatically refetches
164
+ * };
165
+ *
166
+ * const handleDelete = async (id: number) => {
167
+ * await remove(id);
168
+ * // List automatically refetches
169
+ * };
170
+ *
171
+ * return (
172
+ * <div>
173
+ * <button onClick={handleCreate}>Create Task</button>
174
+ * {items.map(task => (
175
+ * <div key={task.Id}>
176
+ * <span>{task.Title}</span>
177
+ * <button onClick={() => handleUpdate(task.Id)}>Complete</button>
178
+ * <button onClick={() => handleDelete(task.Id)}>Delete</button>
179
+ * </div>
180
+ * ))}
181
+ * </div>
182
+ * );
183
+ * }
184
+ * ```
185
+ *
186
+ * @example Batch operations for bulk updates
187
+ * ```tsx
188
+ * function BulkTaskManager() {
189
+ * const { createBatch, updateBatch, removeBatch } = useSPFxPnPList<Task>('Tasks');
190
+ *
191
+ * const handleBulkCreate = async () => {
192
+ * const ids = await createBatch([
193
+ * { Title: 'Task 1', Status: 'Active', Priority: 1 },
194
+ * { Title: 'Task 2', Status: 'Active', Priority: 2 },
195
+ * { Title: 'Task 3', Status: 'Active', Priority: 3 }
196
+ * ]);
197
+ * console.log('Created task IDs:', ids);
198
+ * };
199
+ *
200
+ * const handleBulkUpdate = async (taskIds: number[]) => {
201
+ * await updateBatch([
202
+ * { id: taskIds[0], item: { Status: 'Completed' } },
203
+ * { id: taskIds[1], item: { Priority: 5 } },
204
+ * { id: taskIds[2], item: { Status: 'In Progress', Priority: 4 } }
205
+ * ]);
206
+ * };
207
+ *
208
+ * const handleBulkDelete = async (taskIds: number[]) => {
209
+ * await removeBatch(taskIds);
210
+ * };
211
+ *
212
+ * return (
213
+ * <div>
214
+ * <button onClick={handleBulkCreate}>Create 3 Tasks</button>
215
+ * </div>
216
+ * );
217
+ * }
218
+ * ```
219
+ *
220
+ * @example Pagination with loadMore
221
+ * ```tsx
222
+ * function InfiniteTaskList() {
223
+ * const {
224
+ * query,
225
+ * items,
226
+ * loading,
227
+ * loadingMore,
228
+ * hasMore,
229
+ * loadMore,
230
+ * isEmpty
231
+ * } = useSPFxPnPList<Task>('Tasks', { pageSize: 50 });
232
+ *
233
+ * useEffect(() => {
234
+ * query(q =>
235
+ * q.select('Id', 'Title', 'Status')
236
+ * .orderBy('Created', false)
237
+ * );
238
+ * }, [query]);
239
+ *
240
+ * if (loading) return <Spinner label="Loading tasks..." />;
241
+ * if (isEmpty) return <MessageBar>No tasks found</MessageBar>;
242
+ *
243
+ * return (
244
+ * <div>
245
+ * {items.map(task => (
246
+ * <TaskCard key={task.Id} task={task} />
247
+ * ))}
248
+ *
249
+ * {hasMore && (
250
+ * <PrimaryButton
251
+ * text={loadingMore ? 'Loading...' : 'Load More'}
252
+ * onClick={loadMore}
253
+ * disabled={loadingMore}
254
+ * />
255
+ * )}
256
+ * </div>
257
+ * );
258
+ * }
259
+ * ```
260
+ *
261
+ * @example Cross-site usage
262
+ * ```tsx
263
+ * function EmployeeList() {
264
+ * // Create context for HR site
265
+ * const hrContext = useSPFxPnPContext({
266
+ * siteUrl: '/sites/hr'
267
+ * });
268
+ *
269
+ * // Query Employees list from HR site
270
+ * const { query, items, loading } = useSPFxPnPList<Employee>(
271
+ * 'Employees',
272
+ * { pageSize: 100 },
273
+ * hrContext // Pass context for cross-site query
274
+ * );
275
+ *
276
+ * useEffect(() => {
277
+ * query(q =>
278
+ * q.select('Id', 'Name', 'Department', 'Email')
279
+ * .filter("Department eq 'Engineering'")
280
+ * .orderBy('Name', true)
281
+ * );
282
+ * }, [query]);
283
+ *
284
+ * return (
285
+ * <div>
286
+ * {items.map(emp => (
287
+ * <PersonaCard key={emp.Id} employee={emp} />
288
+ * ))}
289
+ * </div>
290
+ * );
291
+ * }
292
+ * ```
293
+ *
294
+ * @example Manual refetch with error handling
295
+ * ```tsx
296
+ * function TaskListWithRefresh() {
297
+ * const { query, items, loading, error, refetch, clearError } = useSPFxPnPList<Task>('Tasks', { pageSize: 50 });
298
+ *
299
+ * useEffect(() => {
300
+ * query(q => q.select('Id', 'Title', 'Status').orderBy('Created', false));
301
+ * }, [query]);
302
+ *
303
+ * return (
304
+ * <div>
305
+ * <CommandBar
306
+ * items={[
307
+ * {
308
+ * key: 'refresh',
309
+ * text: 'Refresh',
310
+ * iconProps: { iconName: 'Refresh' },
311
+ * onClick: () => refetch()
312
+ * }
313
+ * ]}
314
+ * />
315
+ *
316
+ * {error && (
317
+ * <MessageBar
318
+ * messageBarType={MessageBarType.error}
319
+ * onDismiss={clearError}
320
+ * >
321
+ * Error loading tasks: {error.message}
322
+ * </MessageBar>
323
+ * )}
324
+ *
325
+ * {loading ? (
326
+ * <Spinner />
327
+ * ) : (
328
+ * <DetailsList items={items} />
329
+ * )}
330
+ * </div>
331
+ * );
332
+ * }
333
+ * ```
334
+ *
335
+ * @example Conditional loading (autoLoad: false)
336
+ * ```tsx
337
+ * function ConditionalTaskList() {
338
+ * const [showCompleted, setShowCompleted] = useState(false);
339
+ * const { items, loading, refetch } = useSPFxPnPList<Task>(
340
+ * 'Tasks',
341
+ * {
342
+ * filter: showCompleted ? "Status eq 'Completed'" : "Status eq 'Active'",
343
+ * autoLoad: false // Don't load on mount
344
+ * }
345
+ * );
346
+ *
347
+ * useEffect(() => {
348
+ * if (showCompleted) {
349
+ * refetch(); // Manually trigger load
350
+ * }
351
+ * }, [showCompleted, refetch]);
352
+ *
353
+ * return (
354
+ * <div>
355
+ * <Toggle
356
+ * label="Show Completed"
357
+ * checked={showCompleted}
358
+ * onChange={(_, checked) => setShowCompleted(checked || false)}
359
+ * />
360
+ * {items.map(task => <TaskCard key={task.Id} task={task} />)}
361
+ * </div>
362
+ * );
363
+ * }
364
+ * ```
365
+ *
366
+ * @remarks
367
+ * **PnPjs Installation**: This hook requires `@pnp/sp` to be installed:
368
+ * ```bash
369
+ * npm install @pnp/sp @pnp/core @pnp/queryable
370
+ * ```
371
+ *
372
+ * **SharePoint List View Threshold**: Be aware that querying lists with more than 5000 items
373
+ * may cause throttling unless:
374
+ * - Filters use indexed columns
375
+ * - Query results are under 5000 items
376
+ * - Proper pagination is used (top + skip)
377
+ *
378
+ * **Fluent Filter Requirements**: To use type-safe fluent filters, import types:
379
+ * ```typescript
380
+ * import '@pnp/sp/items'; // Enables fluent filter on items
381
+ * ```
382
+ *
383
+ * **State Management**: Each hook instance maintains its own local state (items, loading, error).
384
+ * State is not shared between components - this follows the standard React hooks pattern.
385
+ *
386
+ * **Debounced Refetch**: CRUD operations trigger a debounced refetch (100ms delay) to prevent
387
+ * race conditions when multiple operations occur in quick succession.
388
+ *
389
+ * @see {@link useSPFxPnPContext} for creating PnP contexts
390
+ * @see {@link PNPContextInfo} for context information
391
+ */
392
+ export function useSPFxPnPList(listTitle, options, pnpContext) {
393
+ var _this = this;
394
+ // Get PnP context (use provided context or create default)
395
+ var defaultContext = useSPFxPnPContext();
396
+ var context = pnpContext || defaultContext;
397
+ // Use the native SPFI instance from context
398
+ var sp = context === null || context === void 0 ? void 0 : context.sp;
399
+ // Default pageSize from hook options
400
+ var defaultPageSize = options === null || options === void 0 ? void 0 : options.pageSize;
401
+ // Local state management
402
+ var _a = useState([]), items = _a[0], setItems = _a[1];
403
+ var _b = useState(false), loading = _b[0], setLoading = _b[1];
404
+ var _c = useState(false), loadingMore = _c[0], setLoadingMore = _c[1];
405
+ var _d = useState(), error = _d[0], setError = _d[1];
406
+ var _e = useState(false), hasMore = _e[0], setHasMore = _e[1];
407
+ // State for tracking last query (needed for refetch and loadMore)
408
+ var _f = useState(undefined), lastQueryBuilder = _f[0], setLastQueryBuilder = _f[1];
409
+ var _g = useState(undefined), lastEffectivePageSize = _g[0], setLastEffectivePageSize = _g[1];
410
+ var _h = useState(0), currentSkip = _h[0], setCurrentSkip = _h[1];
411
+ // Refs
412
+ var refetchTimeoutRef = useRef(undefined);
413
+ var mountedRef = useRef(true);
414
+ // Clear error handler
415
+ var clearError = useCallback(function () {
416
+ setError(undefined);
417
+ }, []);
418
+ /**
419
+ * Helper: Creates a recursive Proxy to track .top() calls in queryBuilder.
420
+ * This allows automatic detection of user-specified page size.
421
+ */
422
+ var createMonitoredQuery = useCallback(function (target, tracker) {
423
+ /* eslint-disable @typescript-eslint/no-explicit-any */
424
+ return new Proxy(target, {
425
+ get: function (t, prop) {
426
+ if (prop === 'top') {
427
+ return function (n) {
428
+ tracker.top = n;
429
+ var result = t.top.call(t, n);
430
+ return createMonitoredQuery(result, tracker);
431
+ };
432
+ }
433
+ var value = t[prop];
434
+ if (typeof value === 'function') {
435
+ return function () {
436
+ var args = [];
437
+ for (var _i = 0; _i < arguments.length; _i++) {
438
+ args[_i] = arguments[_i];
439
+ }
440
+ var result = value.apply(t, args);
441
+ if (result && typeof result === 'object' && typeof result.select === 'function') {
442
+ return createMonitoredQuery(result, tracker);
443
+ }
444
+ return result;
445
+ };
446
+ }
447
+ return value;
448
+ }
449
+ });
450
+ /* eslint-enable @typescript-eslint/no-explicit-any */
451
+ }, []);
452
+ /**
453
+ * Executes a query with automatic .top() detection.
454
+ */
455
+ var query = useCallback(function (queryBuilder, queryOptions) { return __awaiter(_this, void 0, void 0, function () {
456
+ var err, pageSize, baseQuery, tracker, monitored, userQuery, finalQuery, effectivePageSize, result, err_1;
457
+ var _a;
458
+ return __generator(this, function (_b) {
459
+ switch (_b.label) {
460
+ case 0:
461
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
462
+ err = new Error('[useSPFxPnPList] PnP context not initialized. Ensure @pnp/sp is installed.');
463
+ setError(err);
464
+ throw err;
465
+ }
466
+ setLoading(true);
467
+ setError(undefined);
468
+ _b.label = 1;
469
+ case 1:
470
+ _b.trys.push([1, 3, , 4]);
471
+ pageSize = (_a = queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.pageSize) !== null && _a !== void 0 ? _a : defaultPageSize;
472
+ baseQuery = sp.web.lists.getByTitle(listTitle).items;
473
+ tracker = { top: undefined };
474
+ monitored = createMonitoredQuery(baseQuery, tracker);
475
+ userQuery = queryBuilder ? queryBuilder(monitored) : monitored;
476
+ finalQuery = void 0;
477
+ effectivePageSize = void 0;
478
+ // Warning if both specified
479
+ if (tracker.top !== undefined && pageSize !== undefined) {
480
+ console.warn("[useSPFxPnPList] Both .top(".concat(tracker.top, ") and pageSize(").concat(pageSize, ") specified. ") +
481
+ "Using .top(".concat(tracker.top, ")."));
482
+ }
483
+ if (tracker.top !== undefined) {
484
+ // User specified .top() explicitly
485
+ finalQuery = userQuery;
486
+ effectivePageSize = tracker.top;
487
+ }
488
+ else if (pageSize !== undefined) {
489
+ // Use pageSize option
490
+ finalQuery = userQuery.top(pageSize);
491
+ effectivePageSize = pageSize;
492
+ }
493
+ else {
494
+ // No pagination
495
+ finalQuery = userQuery;
496
+ effectivePageSize = undefined;
497
+ }
498
+ return [4 /*yield*/, finalQuery()];
499
+ case 2:
500
+ result = _b.sent();
501
+ if (!mountedRef.current)
502
+ return [2 /*return*/, result];
503
+ // Update state
504
+ setItems(result);
505
+ setLastQueryBuilder(function () { return queryBuilder; });
506
+ setLastEffectivePageSize(effectivePageSize);
507
+ setCurrentSkip(result.length);
508
+ // hasMore only meaningful with pagination
509
+ if (effectivePageSize !== undefined) {
510
+ setHasMore(result.length === effectivePageSize);
511
+ }
512
+ else {
513
+ setHasMore(false);
514
+ }
515
+ setLoading(false);
516
+ return [2 /*return*/, result];
517
+ case 3:
518
+ err_1 = _b.sent();
519
+ if (mountedRef.current) {
520
+ setError(err_1);
521
+ setLoading(false);
522
+ }
523
+ throw err_1;
524
+ case 4: return [2 /*return*/];
525
+ }
526
+ });
527
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, defaultPageSize, createMonitoredQuery]);
528
+ /**
529
+ * Re-executes the last query (resets pagination).
530
+ */
531
+ var refetch = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
532
+ return __generator(this, function (_a) {
533
+ switch (_a.label) {
534
+ case 0:
535
+ if (!lastQueryBuilder) {
536
+ throw new Error('[useSPFxPnPList] No previous query to refetch. Call query() first.');
537
+ }
538
+ setCurrentSkip(0);
539
+ return [4 /*yield*/, query(lastQueryBuilder, { pageSize: lastEffectivePageSize })];
540
+ case 1:
541
+ _a.sent();
542
+ return [2 /*return*/];
543
+ }
544
+ });
545
+ }); }, [lastQueryBuilder, lastEffectivePageSize, query]);
546
+ /**
547
+ * Debounced refetch to prevent race conditions during rapid CRUD operations.
548
+ */
549
+ var debouncedRefetch = useCallback(function () {
550
+ if (refetchTimeoutRef.current) {
551
+ clearTimeout(refetchTimeoutRef.current);
552
+ }
553
+ refetchTimeoutRef.current = setTimeout(function () {
554
+ refetch().catch(function (err) {
555
+ var error = err;
556
+ console.error('[useSPFxPnPList] Debounced refetch error:', error);
557
+ setError(error);
558
+ });
559
+ }, 100);
560
+ }, [refetch]);
561
+ /**
562
+ * Loads more items (pagination with last query).
563
+ */
564
+ var loadMore = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
565
+ var baseQuery, tracker, monitored, userQuery, finalQuery, result_1, err_2;
566
+ return __generator(this, function (_a) {
567
+ switch (_a.label) {
568
+ case 0:
569
+ if (!lastQueryBuilder) {
570
+ throw new Error('[useSPFxPnPList] No previous query. Call query() first.');
571
+ }
572
+ if (lastEffectivePageSize === undefined) {
573
+ throw new Error('[useSPFxPnPList] Cannot loadMore without pageSize. Specify .top() or pageSize option in query().');
574
+ }
575
+ if (loadingMore || loading) {
576
+ return [2 /*return*/, []];
577
+ }
578
+ setLoadingMore(true);
579
+ _a.label = 1;
580
+ case 1:
581
+ _a.trys.push([1, 3, , 4]);
582
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
583
+ throw new Error('[useSPFxPnPList] PnP context not initialized');
584
+ }
585
+ baseQuery = sp.web.lists.getByTitle(listTitle).items;
586
+ tracker = { top: undefined };
587
+ monitored = createMonitoredQuery(baseQuery, tracker);
588
+ userQuery = lastQueryBuilder(monitored);
589
+ finalQuery = userQuery.skip(currentSkip).top(lastEffectivePageSize);
590
+ return [4 /*yield*/, finalQuery()];
591
+ case 2:
592
+ result_1 = _a.sent();
593
+ if (!mountedRef.current)
594
+ return [2 /*return*/, result_1];
595
+ setItems(function (prevItems) {
596
+ return prevItems.concat(result_1);
597
+ });
598
+ setCurrentSkip(function (prev) {
599
+ return prev + result_1.length;
600
+ });
601
+ setHasMore(result_1.length === lastEffectivePageSize);
602
+ setLoadingMore(false);
603
+ return [2 /*return*/, result_1];
604
+ case 3:
605
+ err_2 = _a.sent();
606
+ if (mountedRef.current) {
607
+ setError(err_2);
608
+ setLoadingMore(false);
609
+ }
610
+ throw err_2;
611
+ case 4: return [2 /*return*/];
612
+ }
613
+ });
614
+ }); }, [lastQueryBuilder, lastEffectivePageSize, loadingMore, loading, sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, currentSkip, createMonitoredQuery]);
615
+ /**
616
+ * Gets a single item by ID.
617
+ */
618
+ var getById = useCallback(function (id) { return __awaiter(_this, void 0, void 0, function () {
619
+ var item, err_3, error_1;
620
+ return __generator(this, function (_a) {
621
+ switch (_a.label) {
622
+ case 0:
623
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
624
+ throw new Error('[useSPFxPnPList] PnP context not initialized');
625
+ }
626
+ _a.label = 1;
627
+ case 1:
628
+ _a.trys.push([1, 3, , 4]);
629
+ return [4 /*yield*/, sp.web.lists.getByTitle(listTitle).items.getById(id)()];
630
+ case 2:
631
+ item = _a.sent();
632
+ return [2 /*return*/, item];
633
+ case 3:
634
+ err_3 = _a.sent();
635
+ error_1 = err_3;
636
+ console.error('[useSPFxPnPList] getById error:', error_1);
637
+ setError(error_1);
638
+ return [2 /*return*/, undefined];
639
+ case 4: return [2 /*return*/];
640
+ }
641
+ });
642
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle]);
643
+ /**
644
+ * Creates a new list item.
645
+ */
646
+ var create = useCallback(function (item) { return __awaiter(_this, void 0, void 0, function () {
647
+ var result, err_4;
648
+ return __generator(this, function (_a) {
649
+ switch (_a.label) {
650
+ case 0:
651
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
652
+ throw new Error('PnP context not initialized');
653
+ }
654
+ _a.label = 1;
655
+ case 1:
656
+ _a.trys.push([1, 3, , 4]);
657
+ return [4 /*yield*/, sp.web.lists.getByTitle(listTitle).items.add(item)];
658
+ case 2:
659
+ result = _a.sent();
660
+ debouncedRefetch();
661
+ return [2 /*return*/, result.data.Id];
662
+ case 3:
663
+ err_4 = _a.sent();
664
+ setError(err_4);
665
+ throw err_4;
666
+ case 4: return [2 /*return*/];
667
+ }
668
+ });
669
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, debouncedRefetch]);
670
+ /**
671
+ * Updates an existing list item.
672
+ */
673
+ var update = useCallback(function (id, item) { return __awaiter(_this, void 0, void 0, function () {
674
+ var err_5;
675
+ return __generator(this, function (_a) {
676
+ switch (_a.label) {
677
+ case 0:
678
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
679
+ throw new Error('PnP context not initialized');
680
+ }
681
+ _a.label = 1;
682
+ case 1:
683
+ _a.trys.push([1, 3, , 4]);
684
+ return [4 /*yield*/, sp.web.lists.getByTitle(listTitle).items.getById(id).update(item)];
685
+ case 2:
686
+ _a.sent();
687
+ debouncedRefetch();
688
+ return [3 /*break*/, 4];
689
+ case 3:
690
+ err_5 = _a.sent();
691
+ setError(err_5);
692
+ throw err_5;
693
+ case 4: return [2 /*return*/];
694
+ }
695
+ });
696
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, debouncedRefetch]);
697
+ /**
698
+ * Deletes a list item.
699
+ */
700
+ var remove = useCallback(function (id) { return __awaiter(_this, void 0, void 0, function () {
701
+ var err_6;
702
+ return __generator(this, function (_a) {
703
+ switch (_a.label) {
704
+ case 0:
705
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
706
+ throw new Error('PnP context not initialized');
707
+ }
708
+ _a.label = 1;
709
+ case 1:
710
+ _a.trys.push([1, 3, , 4]);
711
+ return [4 /*yield*/, sp.web.lists.getByTitle(listTitle).items.getById(id).delete()];
712
+ case 2:
713
+ _a.sent();
714
+ debouncedRefetch();
715
+ return [3 /*break*/, 4];
716
+ case 3:
717
+ err_6 = _a.sent();
718
+ setError(err_6);
719
+ throw err_6;
720
+ case 4: return [2 /*return*/];
721
+ }
722
+ });
723
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, debouncedRefetch]);
724
+ /**
725
+ * Creates multiple items in a batch.
726
+ */
727
+ var createBatch = useCallback(function (itemsToCreate) { return __awaiter(_this, void 0, void 0, function () {
728
+ var ids_1, errors_1, batchResult, batchedSP, execute, list, i, batchError, err_7, error_2;
729
+ return __generator(this, function (_a) {
730
+ switch (_a.label) {
731
+ case 0:
732
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
733
+ throw new Error('PnP context not initialized');
734
+ }
735
+ _a.label = 1;
736
+ case 1:
737
+ _a.trys.push([1, 3, , 4]);
738
+ ids_1 = [];
739
+ errors_1 = [];
740
+ batchResult = sp.batched();
741
+ batchedSP = batchResult[0];
742
+ execute = batchResult[1];
743
+ list = batchedSP.web.lists.getByTitle(listTitle);
744
+ // Queue all creates
745
+ for (i = 0; i < itemsToCreate.length; i++) {
746
+ list.items.add(itemsToCreate[i]).then(function (result) {
747
+ ids_1.push(result.data.Id);
748
+ }).catch(function (error) {
749
+ console.error('Batch create error:', error);
750
+ errors_1.push(error);
751
+ });
752
+ }
753
+ // Execute batch
754
+ return [4 /*yield*/, execute()];
755
+ case 2:
756
+ // Execute batch
757
+ _a.sent();
758
+ // If there were errors in individual operations, set error state
759
+ if (errors_1.length > 0) {
760
+ batchError = new Error("Batch create failed: ".concat(errors_1.length, " of ").concat(itemsToCreate.length, " items failed"));
761
+ setError(batchError);
762
+ console.error('Batch create summary:', errors_1);
763
+ }
764
+ debouncedRefetch();
765
+ return [2 /*return*/, ids_1];
766
+ case 3:
767
+ err_7 = _a.sent();
768
+ error_2 = err_7;
769
+ setError(error_2);
770
+ throw error_2;
771
+ case 4: return [2 /*return*/];
772
+ }
773
+ });
774
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, debouncedRefetch]);
775
+ /**
776
+ * Updates multiple items in a batch.
777
+ */
778
+ var updateBatch = useCallback(function (updates) { return __awaiter(_this, void 0, void 0, function () {
779
+ var errors_2, batchResult, batchedSP, execute, list, i, updateItem, batchError, err_8, error_3;
780
+ return __generator(this, function (_a) {
781
+ switch (_a.label) {
782
+ case 0:
783
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
784
+ throw new Error('PnP context not initialized');
785
+ }
786
+ _a.label = 1;
787
+ case 1:
788
+ _a.trys.push([1, 3, , 4]);
789
+ errors_2 = [];
790
+ batchResult = sp.batched();
791
+ batchedSP = batchResult[0];
792
+ execute = batchResult[1];
793
+ list = batchedSP.web.lists.getByTitle(listTitle);
794
+ // Queue all updates
795
+ for (i = 0; i < updates.length; i++) {
796
+ updateItem = updates[i];
797
+ list.items.getById(updateItem.id).update(updateItem.item).catch(function (error) {
798
+ console.error('Batch update error:', error);
799
+ errors_2.push(error);
800
+ });
801
+ }
802
+ // Execute batch
803
+ return [4 /*yield*/, execute()];
804
+ case 2:
805
+ // Execute batch
806
+ _a.sent();
807
+ // If there were errors in individual operations, set error state
808
+ if (errors_2.length > 0) {
809
+ batchError = new Error("Batch update failed: ".concat(errors_2.length, " of ").concat(updates.length, " items failed"));
810
+ setError(batchError);
811
+ console.error('Batch update summary:', errors_2);
812
+ }
813
+ debouncedRefetch();
814
+ return [3 /*break*/, 4];
815
+ case 3:
816
+ err_8 = _a.sent();
817
+ error_3 = err_8;
818
+ setError(error_3);
819
+ throw error_3;
820
+ case 4: return [2 /*return*/];
821
+ }
822
+ });
823
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, debouncedRefetch]);
824
+ /**
825
+ * Deletes multiple items in a batch.
826
+ */
827
+ var removeBatch = useCallback(function (ids) { return __awaiter(_this, void 0, void 0, function () {
828
+ var errors_3, batchResult, batchedSP, execute, list, i, batchError, err_9, error_4;
829
+ return __generator(this, function (_a) {
830
+ switch (_a.label) {
831
+ case 0:
832
+ if (!sp || !(context === null || context === void 0 ? void 0 : context.isInitialized)) {
833
+ throw new Error('PnP context not initialized');
834
+ }
835
+ _a.label = 1;
836
+ case 1:
837
+ _a.trys.push([1, 3, , 4]);
838
+ errors_3 = [];
839
+ batchResult = sp.batched();
840
+ batchedSP = batchResult[0];
841
+ execute = batchResult[1];
842
+ list = batchedSP.web.lists.getByTitle(listTitle);
843
+ // Queue all deletes
844
+ for (i = 0; i < ids.length; i++) {
845
+ list.items.getById(ids[i]).delete().catch(function (error) {
846
+ console.error('Batch delete error:', error);
847
+ errors_3.push(error);
848
+ });
849
+ }
850
+ // Execute batch
851
+ return [4 /*yield*/, execute()];
852
+ case 2:
853
+ // Execute batch
854
+ _a.sent();
855
+ // If there were errors in individual operations, set error state
856
+ if (errors_3.length > 0) {
857
+ batchError = new Error("Batch delete failed: ".concat(errors_3.length, " of ").concat(ids.length, " items failed"));
858
+ setError(batchError);
859
+ console.error('Batch delete summary:', errors_3);
860
+ }
861
+ debouncedRefetch();
862
+ return [3 /*break*/, 4];
863
+ case 3:
864
+ err_9 = _a.sent();
865
+ error_4 = err_9;
866
+ setError(error_4);
867
+ throw error_4;
868
+ case 4: return [2 /*return*/];
869
+ }
870
+ });
871
+ }); }, [sp, context === null || context === void 0 ? void 0 : context.isInitialized, listTitle, debouncedRefetch]);
872
+ /**
873
+ * Cleanup on unmount.
874
+ */
875
+ useEffect(function () {
876
+ mountedRef.current = true;
877
+ return function () {
878
+ mountedRef.current = false;
879
+ if (refetchTimeoutRef.current) {
880
+ clearTimeout(refetchTimeoutRef.current);
881
+ }
882
+ };
883
+ }, []);
884
+ // Derived state
885
+ var isEmpty = items.length === 0 && !loading && !error;
886
+ return {
887
+ query: query,
888
+ items: items,
889
+ loading: loading,
890
+ loadingMore: loadingMore,
891
+ error: error,
892
+ isEmpty: isEmpty,
893
+ hasMore: hasMore,
894
+ refetch: refetch,
895
+ loadMore: loadMore,
896
+ clearError: clearError,
897
+ getById: getById,
898
+ create: create,
899
+ update: update,
900
+ remove: remove,
901
+ createBatch: createBatch,
902
+ updateBatch: updateBatch,
903
+ removeBatch: removeBatch,
904
+ };
905
+ }
906
+ //# sourceMappingURL=useSPFxPnPList.js.map