@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,545 @@
1
+ import type { PnPContextInfo } from './useSPFxPnPContext';
2
+ import type { IItems } from '@pnp/sp/items';
3
+ import type { InitialFieldQuery, ComparisonResult } from '@pnp/sp/spqueryable';
4
+ /**
5
+ * Type representing a fluent filter function for type-safe query building.
6
+ * Uses native PnPjs v4 fluent filter API types.
7
+ *
8
+ * @template T - The type of the list item
9
+ * @example
10
+ * ```tsx
11
+ * interface Task {
12
+ * Status: string;
13
+ * Priority: number;
14
+ * }
15
+ *
16
+ * const filterFn: ListFilterFunction<Task> = (f) =>
17
+ * f.text("Status").equals("Active")
18
+ * .and()
19
+ * .number("Priority").greaterThan(3);
20
+ * ```
21
+ */
22
+ export type ListFilterFunction<T> = (f: InitialFieldQuery<T>) => ComparisonResult<T>;
23
+ /**
24
+ * Options for configuring the useSPFxPnPList hook.
25
+ */
26
+ export interface UseSPFxPnPListOptions {
27
+ /**
28
+ * Page size for pagination (number of items per page).
29
+ * Used by `loadMore()` for automatic pagination.
30
+ *
31
+ * @default 100
32
+ * @example
33
+ * ```tsx
34
+ * const { query, loadMore } = useSPFxPnPList('Tasks', { pageSize: 50 });
35
+ * ```
36
+ */
37
+ pageSize?: number;
38
+ }
39
+ /**
40
+ * Return type for the useSPFxPnPList hook.
41
+ *
42
+ * @template T - The type of the list item
43
+ */
44
+ export interface SPFxPnPListInfo<T = unknown> {
45
+ /**
46
+ * Executes a query against the SharePoint list using PnPjs fluent API.
47
+ *
48
+ * The hook automatically detects if `.top()` is called in the queryBuilder:
49
+ * - If `.top()` is specified → uses that value
50
+ * - If no `.top()` → uses `pageSize` option (if provided)
51
+ * - If neither → no limit (SharePoint default ~100-5000)
52
+ *
53
+ * **Note**: If both `.top()` and `pageSize` are specified, `.top()` takes precedence
54
+ * and a warning is logged to the console.
55
+ *
56
+ * @param queryBuilder - Function to build the query using PnPjs fluent API
57
+ * @param options - Query options (pageSize for pagination)
58
+ * @returns Promise resolving to the array of items
59
+ *
60
+ * @example Basic query with pageSize
61
+ * ```tsx
62
+ * const { query, items } = useSPFxPnPList('Tasks', { pageSize: 50 });
63
+ *
64
+ * await query(q =>
65
+ * q.select('Id', 'Title', 'Status')
66
+ * .filter("Status eq 'Active'")
67
+ * .orderBy('Created', false)
68
+ * );
69
+ * ```
70
+ *
71
+ * @example Query with explicit .top()
72
+ * ```tsx
73
+ * await query(q =>
74
+ * q.select('Id', 'Title')
75
+ * .top(100) // Explicit top takes precedence
76
+ * .orderBy('Priority', false)
77
+ * );
78
+ * ```
79
+ *
80
+ * @example Query without pagination
81
+ * ```tsx
82
+ * await query(q => q.select('Id', 'Title'));
83
+ * // Uses SharePoint default limit
84
+ * ```
85
+ */
86
+ query: (queryBuilder?: (items: IItems) => IItems, options?: {
87
+ pageSize?: number;
88
+ }) => Promise<T[]>;
89
+ /**
90
+ * Array of list items returned from the last query.
91
+ */
92
+ items: T[];
93
+ /**
94
+ * Indicates if a query is in progress.
95
+ */
96
+ loading: boolean;
97
+ /**
98
+ * Indicates if additional items are being loaded via loadMore().
99
+ */
100
+ loadingMore: boolean;
101
+ /**
102
+ * Error object if an error occurred during any operation.
103
+ */
104
+ error: Error | undefined;
105
+ /**
106
+ * Indicates if the items array is empty.
107
+ */
108
+ isEmpty: boolean;
109
+ /**
110
+ * Indicates if there are more items available to load.
111
+ * Only meaningful when using pagination (pageSize or .top()).
112
+ */
113
+ hasMore: boolean;
114
+ /**
115
+ * Re-executes the last query with the same parameters.
116
+ * Resets pagination state.
117
+ *
118
+ * @returns Promise resolving when refetch is complete
119
+ * @throws Error if no previous query was executed
120
+ */
121
+ refetch: () => Promise<void>;
122
+ /**
123
+ * Loads the next page of items using the last query.
124
+ * Automatically appends new items to the existing items array.
125
+ *
126
+ * @returns Promise resolving to the newly loaded items
127
+ * @throws Error if no previous query was executed
128
+ * @throws Error if no pageSize was specified in the previous query
129
+ */
130
+ loadMore: () => Promise<T[]>;
131
+ /**
132
+ * Clears the current error state.
133
+ */
134
+ clearError: () => void;
135
+ /**
136
+ * Retrieves a single list item by ID.
137
+ *
138
+ * @param id - The ID of the list item to retrieve
139
+ * @returns Promise resolving to the item or undefined if not found
140
+ */
141
+ getById: (id: number) => Promise<T | undefined>;
142
+ /**
143
+ * Creates a new list item.
144
+ * Automatically triggers a refetch after successful creation.
145
+ *
146
+ * @param item - Partial object containing the fields to set
147
+ * @returns Promise resolving to the ID of the created item
148
+ */
149
+ create: (item: Partial<T>) => Promise<number>;
150
+ /**
151
+ * Updates an existing list item by ID.
152
+ * Automatically triggers a refetch after successful update.
153
+ *
154
+ * @param id - The ID of the list item to update
155
+ * @param item - Partial object containing the fields to update
156
+ */
157
+ update: (id: number, item: Partial<T>) => Promise<void>;
158
+ /**
159
+ * Deletes a list item by ID.
160
+ * Automatically triggers a refetch after successful deletion.
161
+ *
162
+ * @param id - The ID of the list item to delete
163
+ */
164
+ remove: (id: number) => Promise<void>;
165
+ /**
166
+ * Creates multiple list items in a single batched request.
167
+ * Automatically triggers a refetch after successful batch creation.
168
+ *
169
+ * @param items - Array of partial objects to create
170
+ * @returns Promise resolving to an array of created item IDs
171
+ */
172
+ createBatch: (items: Partial<T>[]) => Promise<number[]>;
173
+ /**
174
+ * Updates multiple list items in a single batched request.
175
+ * Automatically triggers a refetch after successful batch update.
176
+ *
177
+ * @param updates - Array of objects containing id and item fields to update
178
+ */
179
+ updateBatch: (updates: Array<{
180
+ id: number;
181
+ item: Partial<T>;
182
+ }>) => Promise<void>;
183
+ /**
184
+ * Deletes multiple list items in a single batched request.
185
+ * Automatically triggers a refetch after successful batch deletion.
186
+ *
187
+ * @param ids - Array of item IDs to delete
188
+ */
189
+ removeBatch: (ids: number[]) => Promise<void>;
190
+ }
191
+ /**
192
+ * Hook for working with SharePoint lists using PnPjs fluent API.
193
+ * Provides query execution with automatic .top() detection, CRUD operations, pagination, and state management.
194
+ *
195
+ * **Key Features**:
196
+ * - ✅ Native PnPjs fluent API - full type-safe query building
197
+ * - ✅ Smart .top() detection - no conflicts between user .top() and pageSize
198
+ * - ✅ CRUD operations (create, read, update, delete)
199
+ * - ✅ Batch operations for bulk updates
200
+ * - ✅ Pagination with `loadMore()` and `hasMore`
201
+ * - ✅ Automatic refetch after CRUD operations
202
+ * - ✅ Local state management per component instance
203
+ * - ✅ Cross-site support via PnPContextInfo
204
+ * - ✅ ES5 compatibility (IE11 support)
205
+ *
206
+ * **How .top() Detection Works**:
207
+ * The hook uses a recursive Proxy to detect if `.top()` is called in your queryBuilder:
208
+ * - If `.top()` is specified → uses that value
209
+ * - If no `.top()` but `pageSize` option → adds `.top(pageSize)` automatically
210
+ * - If neither → no limit (SharePoint default ~100-5000)
211
+ * - If both → `.top()` wins, warning logged
212
+ *
213
+ * @template T - The type of the list item (default: unknown)
214
+ * @param listTitle - The title of the SharePoint list
215
+ * @param options - Optional configuration (pageSize for pagination)
216
+ * @param pnpContext - Optional PnP context for cross-site scenarios
217
+ * @returns Object containing query method, items, loading states, error, and CRUD operations
218
+ *
219
+ * @example Basic usage with pageSize
220
+ * ```tsx
221
+ * import { useSPFxPnPList } from '@apvee/spfx-react-toolkit';
222
+ *
223
+ * function TaskList() {
224
+ * const { query, items, loading, error } = useSPFxPnPList('Tasks', { pageSize: 50 });
225
+ *
226
+ * useEffect(() => {
227
+ * query(q =>
228
+ * q.select('Id', 'Title', 'Status', 'Priority')
229
+ * .filter("Status eq 'Active'")
230
+ * .orderBy('Priority', false)
231
+ * );
232
+ * }, [query]);
233
+ *
234
+ * if (loading) return <Spinner />;
235
+ * if (error) return <MessageBar>Error: {error.message}</MessageBar>;
236
+ *
237
+ * return (
238
+ * <ul>
239
+ * {items.map(task => (
240
+ * <li key={task.Id}>{task.Title} - {task.Status}</li>
241
+ * ))}
242
+ * </ul>
243
+ * );
244
+ * }
245
+ * ```
246
+ *
247
+ * @example Type-safe fluent filter
248
+ * ```tsx
249
+ * interface Task {
250
+ * Id: number;
251
+ * Title: string;
252
+ * Status: string;
253
+ * Priority: number;
254
+ * DueDate: string;
255
+ * }
256
+ *
257
+ * function ActiveHighPriorityTasks() {
258
+ * const { query, items, loading } = useSPFxPnPList<Task>('Tasks', { pageSize: 50 });
259
+ *
260
+ * useEffect(() => {
261
+ * query(q =>
262
+ * q.select('Id', 'Title', 'Priority', 'DueDate')
263
+ * .filter(f => f.text("Status").equals("Active")
264
+ * .and()
265
+ * .number("Priority").greaterThan(3))
266
+ * .orderBy('DueDate', true)
267
+ * );
268
+ * }, [query]);
269
+ *
270
+ * return (
271
+ * <div>
272
+ * {items.map(task => (
273
+ * <TaskCard key={task.Id} task={task} />
274
+ * ))}
275
+ * </div>
276
+ * );
277
+ * }
278
+ * ```
279
+ *
280
+ * @example Query with explicit .top()
281
+ * ```tsx
282
+ * const { query, items } = useSPFxPnPList<Task>('Tasks');
283
+ *
284
+ * useEffect(() => {
285
+ * // User specifies .top() explicitly - takes precedence
286
+ * query(q =>
287
+ * q.select('Id', 'Title')
288
+ * .top(100) // Hook detects this and uses it
289
+ * .orderBy('Created', false)
290
+ * );
291
+ * }, [query]);
292
+ * ```
293
+ *
294
+ * @example CRUD operations
295
+ * ```tsx
296
+ * function TaskManager() {
297
+ * const { items, create, update, remove, loading } = useSPFxPnPList<Task>('Tasks');
298
+ *
299
+ * const handleCreate = async () => {
300
+ * try {
301
+ * const newId = await create({
302
+ * Title: 'New Task',
303
+ * Status: 'Active',
304
+ * Priority: 3
305
+ * });
306
+ * console.log('Created task with ID:', newId);
307
+ * // List automatically refetches
308
+ * } catch (error) {
309
+ * console.error('Create failed:', error);
310
+ * }
311
+ * };
312
+ *
313
+ * const handleUpdate = async (id: number) => {
314
+ * await update(id, { Status: 'Completed' });
315
+ * // List automatically refetches
316
+ * };
317
+ *
318
+ * const handleDelete = async (id: number) => {
319
+ * await remove(id);
320
+ * // List automatically refetches
321
+ * };
322
+ *
323
+ * return (
324
+ * <div>
325
+ * <button onClick={handleCreate}>Create Task</button>
326
+ * {items.map(task => (
327
+ * <div key={task.Id}>
328
+ * <span>{task.Title}</span>
329
+ * <button onClick={() => handleUpdate(task.Id)}>Complete</button>
330
+ * <button onClick={() => handleDelete(task.Id)}>Delete</button>
331
+ * </div>
332
+ * ))}
333
+ * </div>
334
+ * );
335
+ * }
336
+ * ```
337
+ *
338
+ * @example Batch operations for bulk updates
339
+ * ```tsx
340
+ * function BulkTaskManager() {
341
+ * const { createBatch, updateBatch, removeBatch } = useSPFxPnPList<Task>('Tasks');
342
+ *
343
+ * const handleBulkCreate = async () => {
344
+ * const ids = await createBatch([
345
+ * { Title: 'Task 1', Status: 'Active', Priority: 1 },
346
+ * { Title: 'Task 2', Status: 'Active', Priority: 2 },
347
+ * { Title: 'Task 3', Status: 'Active', Priority: 3 }
348
+ * ]);
349
+ * console.log('Created task IDs:', ids);
350
+ * };
351
+ *
352
+ * const handleBulkUpdate = async (taskIds: number[]) => {
353
+ * await updateBatch([
354
+ * { id: taskIds[0], item: { Status: 'Completed' } },
355
+ * { id: taskIds[1], item: { Priority: 5 } },
356
+ * { id: taskIds[2], item: { Status: 'In Progress', Priority: 4 } }
357
+ * ]);
358
+ * };
359
+ *
360
+ * const handleBulkDelete = async (taskIds: number[]) => {
361
+ * await removeBatch(taskIds);
362
+ * };
363
+ *
364
+ * return (
365
+ * <div>
366
+ * <button onClick={handleBulkCreate}>Create 3 Tasks</button>
367
+ * </div>
368
+ * );
369
+ * }
370
+ * ```
371
+ *
372
+ * @example Pagination with loadMore
373
+ * ```tsx
374
+ * function InfiniteTaskList() {
375
+ * const {
376
+ * query,
377
+ * items,
378
+ * loading,
379
+ * loadingMore,
380
+ * hasMore,
381
+ * loadMore,
382
+ * isEmpty
383
+ * } = useSPFxPnPList<Task>('Tasks', { pageSize: 50 });
384
+ *
385
+ * useEffect(() => {
386
+ * query(q =>
387
+ * q.select('Id', 'Title', 'Status')
388
+ * .orderBy('Created', false)
389
+ * );
390
+ * }, [query]);
391
+ *
392
+ * if (loading) return <Spinner label="Loading tasks..." />;
393
+ * if (isEmpty) return <MessageBar>No tasks found</MessageBar>;
394
+ *
395
+ * return (
396
+ * <div>
397
+ * {items.map(task => (
398
+ * <TaskCard key={task.Id} task={task} />
399
+ * ))}
400
+ *
401
+ * {hasMore && (
402
+ * <PrimaryButton
403
+ * text={loadingMore ? 'Loading...' : 'Load More'}
404
+ * onClick={loadMore}
405
+ * disabled={loadingMore}
406
+ * />
407
+ * )}
408
+ * </div>
409
+ * );
410
+ * }
411
+ * ```
412
+ *
413
+ * @example Cross-site usage
414
+ * ```tsx
415
+ * function EmployeeList() {
416
+ * // Create context for HR site
417
+ * const hrContext = useSPFxPnPContext({
418
+ * siteUrl: '/sites/hr'
419
+ * });
420
+ *
421
+ * // Query Employees list from HR site
422
+ * const { query, items, loading } = useSPFxPnPList<Employee>(
423
+ * 'Employees',
424
+ * { pageSize: 100 },
425
+ * hrContext // Pass context for cross-site query
426
+ * );
427
+ *
428
+ * useEffect(() => {
429
+ * query(q =>
430
+ * q.select('Id', 'Name', 'Department', 'Email')
431
+ * .filter("Department eq 'Engineering'")
432
+ * .orderBy('Name', true)
433
+ * );
434
+ * }, [query]);
435
+ *
436
+ * return (
437
+ * <div>
438
+ * {items.map(emp => (
439
+ * <PersonaCard key={emp.Id} employee={emp} />
440
+ * ))}
441
+ * </div>
442
+ * );
443
+ * }
444
+ * ```
445
+ *
446
+ * @example Manual refetch with error handling
447
+ * ```tsx
448
+ * function TaskListWithRefresh() {
449
+ * const { query, items, loading, error, refetch, clearError } = useSPFxPnPList<Task>('Tasks', { pageSize: 50 });
450
+ *
451
+ * useEffect(() => {
452
+ * query(q => q.select('Id', 'Title', 'Status').orderBy('Created', false));
453
+ * }, [query]);
454
+ *
455
+ * return (
456
+ * <div>
457
+ * <CommandBar
458
+ * items={[
459
+ * {
460
+ * key: 'refresh',
461
+ * text: 'Refresh',
462
+ * iconProps: { iconName: 'Refresh' },
463
+ * onClick: () => refetch()
464
+ * }
465
+ * ]}
466
+ * />
467
+ *
468
+ * {error && (
469
+ * <MessageBar
470
+ * messageBarType={MessageBarType.error}
471
+ * onDismiss={clearError}
472
+ * >
473
+ * Error loading tasks: {error.message}
474
+ * </MessageBar>
475
+ * )}
476
+ *
477
+ * {loading ? (
478
+ * <Spinner />
479
+ * ) : (
480
+ * <DetailsList items={items} />
481
+ * )}
482
+ * </div>
483
+ * );
484
+ * }
485
+ * ```
486
+ *
487
+ * @example Conditional loading (autoLoad: false)
488
+ * ```tsx
489
+ * function ConditionalTaskList() {
490
+ * const [showCompleted, setShowCompleted] = useState(false);
491
+ * const { items, loading, refetch } = useSPFxPnPList<Task>(
492
+ * 'Tasks',
493
+ * {
494
+ * filter: showCompleted ? "Status eq 'Completed'" : "Status eq 'Active'",
495
+ * autoLoad: false // Don't load on mount
496
+ * }
497
+ * );
498
+ *
499
+ * useEffect(() => {
500
+ * if (showCompleted) {
501
+ * refetch(); // Manually trigger load
502
+ * }
503
+ * }, [showCompleted, refetch]);
504
+ *
505
+ * return (
506
+ * <div>
507
+ * <Toggle
508
+ * label="Show Completed"
509
+ * checked={showCompleted}
510
+ * onChange={(_, checked) => setShowCompleted(checked || false)}
511
+ * />
512
+ * {items.map(task => <TaskCard key={task.Id} task={task} />)}
513
+ * </div>
514
+ * );
515
+ * }
516
+ * ```
517
+ *
518
+ * @remarks
519
+ * **PnPjs Installation**: This hook requires `@pnp/sp` to be installed:
520
+ * ```bash
521
+ * npm install @pnp/sp @pnp/core @pnp/queryable
522
+ * ```
523
+ *
524
+ * **SharePoint List View Threshold**: Be aware that querying lists with more than 5000 items
525
+ * may cause throttling unless:
526
+ * - Filters use indexed columns
527
+ * - Query results are under 5000 items
528
+ * - Proper pagination is used (top + skip)
529
+ *
530
+ * **Fluent Filter Requirements**: To use type-safe fluent filters, import types:
531
+ * ```typescript
532
+ * import '@pnp/sp/items'; // Enables fluent filter on items
533
+ * ```
534
+ *
535
+ * **State Management**: Each hook instance maintains its own local state (items, loading, error).
536
+ * State is not shared between components - this follows the standard React hooks pattern.
537
+ *
538
+ * **Debounced Refetch**: CRUD operations trigger a debounced refetch (100ms delay) to prevent
539
+ * race conditions when multiple operations occur in quick succession.
540
+ *
541
+ * @see {@link useSPFxPnPContext} for creating PnP contexts
542
+ * @see {@link PNPContextInfo} for context information
543
+ */
544
+ export declare function useSPFxPnPList<T = unknown>(listTitle: string, options?: UseSPFxPnPListOptions, pnpContext?: PnPContextInfo): SPFxPnPListInfo<T>;
545
+ //# sourceMappingURL=useSPFxPnPList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSPFxPnPList.d.ts","sourceRoot":"","sources":["../../src/hooks/useSPFxPnPList.ts"],"names":[],"mappings":"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"}