@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,346 @@
1
+ // useSPFxUserPhoto.ts
2
+ // Hook to load user photos from Microsoft Graph API
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __generator = (this && this.__generator) || function (thisArg, body) {
13
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
14
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
15
+ function verb(n) { return function (v) { return step([n, v]); }; }
16
+ function step(op) {
17
+ if (f) throw new TypeError("Generator is already executing.");
18
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
19
+ 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;
20
+ if (y = 0, t) op = [op[0] & 2, t.value];
21
+ switch (op[0]) {
22
+ case 0: case 1: t = op; break;
23
+ case 4: _.label++; return { value: op[1], done: false };
24
+ case 5: _.label++; y = op[1]; op = [0]; continue;
25
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
26
+ default:
27
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
28
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
29
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
30
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
31
+ if (t[2]) _.ops.pop();
32
+ _.trys.pop(); continue;
33
+ }
34
+ op = body.call(thisArg, _);
35
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
36
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
37
+ }
38
+ };
39
+ import { useState, useCallback, useEffect, useRef } from 'react';
40
+ import { useSPFxMSGraphClient } from './useSPFxMSGraphClient';
41
+ /**
42
+ * Hook to load user photos from Microsoft Graph API
43
+ *
44
+ * Provides easy access to user profile photos with automatic blob URL management.
45
+ * Supports loading current user's photo or any user's photo by ID or email.
46
+ *
47
+ * Features:
48
+ * - Current user or specific user by ID/email
49
+ * - Multiple photo sizes (48x48 to 648x648)
50
+ * - Automatic blob URL creation and cleanup
51
+ * - Memory leak prevention (revokes URLs on unmount)
52
+ * - Type-safe with TypeScript
53
+ * - Auto-fetch on mount (configurable)
54
+ * - Manual reload function
55
+ *
56
+ * Microsoft Graph Permissions Required:
57
+ * - **User.Read**: Required for current user's photo (/me/photo)
58
+ * - **User.ReadBasic.All**: Required for other users' photos (/users/{id}/photo)
59
+ * - **User.Read.All**: Alternative permission for other users (more privileged)
60
+ *
61
+ * Permission Notes:
62
+ * - Application must have appropriate Graph API permissions configured in Azure AD
63
+ * - Permissions must be consented by admin or user (depending on permission type)
64
+ * - 404 errors typically mean the user has no photo (not a permission issue)
65
+ * - 403 errors indicate insufficient permissions
66
+ *
67
+ * Graph API Endpoints Used:
68
+ * - Current user: GET /me/photo/{size}/$value
69
+ * - By ID: GET /users/{id}/photo/{size}/$value
70
+ * - By email: GET /users/{email}/photo/{size}/$value
71
+ *
72
+ * @param options - Optional. Configuration for loading specific user's photo
73
+ *
74
+ * @example Current user photo
75
+ * ```tsx
76
+ * function UserAvatar() {
77
+ * const { photoUrl, isLoading, error } = useSPFxUserPhoto();
78
+ *
79
+ * if (isLoading) return <Spinner />;
80
+ * if (error) return <DefaultAvatar />;
81
+ *
82
+ * return <img src={photoUrl} alt="User" style={{ width: 240, height: 240 }} />;
83
+ * }
84
+ * ```
85
+ *
86
+ * @example Specific user by email
87
+ * ```tsx
88
+ * function TeamMemberAvatar({ email }: { email: string }) {
89
+ * const { photoUrl, isLoading } = useSPFxUserPhoto({
90
+ * email,
91
+ * size: '96x96'
92
+ * });
93
+ *
94
+ * return (
95
+ * <div>
96
+ * {isLoading ? (
97
+ * <Spinner />
98
+ * ) : (
99
+ * <img src={photoUrl || '/default-avatar.png'} alt={email} />
100
+ * )}
101
+ * </div>
102
+ * );
103
+ * }
104
+ * ```
105
+ *
106
+ * @example Specific user by ID with reload
107
+ * ```tsx
108
+ * function ProfileCard({ userId }: { userId: string }) {
109
+ * const { photoUrl, reload, isLoading, error } = useSPFxUserPhoto({
110
+ * userId,
111
+ * size: '360x360'
112
+ * });
113
+ *
114
+ * return (
115
+ * <Stack>
116
+ * {error ? (
117
+ * <MessageBar messageBarType={MessageBarType.error}>
118
+ * Failed to load photo: {error.message}
119
+ * </MessageBar>
120
+ * ) : (
121
+ * <img src={photoUrl} alt="Profile" />
122
+ * )}
123
+ *
124
+ * <PrimaryButton
125
+ * onClick={reload}
126
+ * disabled={isLoading}
127
+ * text="Refresh Photo"
128
+ * />
129
+ * </Stack>
130
+ * );
131
+ * }
132
+ * ```
133
+ *
134
+ * @example Multiple sizes for responsive images
135
+ * ```tsx
136
+ * function ResponsiveAvatar() {
137
+ * const small = useSPFxUserPhoto({ size: '96x96' });
138
+ * const large = useSPFxUserPhoto({ size: '240x240' });
139
+ *
140
+ * return (
141
+ * <picture>
142
+ * <source media="(min-width: 768px)" srcSet={large.photoUrl} />
143
+ * <img src={small.photoUrl} alt="User Avatar" />
144
+ * </picture>
145
+ * );
146
+ * }
147
+ * ```
148
+ *
149
+ * @example Lazy loading with manual fetch
150
+ * ```tsx
151
+ * function LazyAvatar({ email }: { email: string }) {
152
+ * const { photoUrl, reload, isLoading } = useSPFxUserPhoto({
153
+ * email,
154
+ * autoFetch: false // Don't load on mount
155
+ * });
156
+ *
157
+ * return (
158
+ * <div>
159
+ * {photoUrl ? (
160
+ * <img src={photoUrl} alt="Avatar" />
161
+ * ) : (
162
+ * <button onClick={reload} disabled={isLoading}>
163
+ * {isLoading ? 'Loading...' : 'Load Photo'}
164
+ * </button>
165
+ * )}
166
+ * </div>
167
+ * );
168
+ * }
169
+ * ```
170
+ *
171
+ * @example With error fallback
172
+ * ```tsx
173
+ * function SafeAvatar() {
174
+ * const { photoUrl, error, isReady } = useSPFxUserPhoto();
175
+ *
176
+ * if (!isReady) {
177
+ * return <Persona text="Loading..." size={PersonaSize.size72} />;
178
+ * }
179
+ *
180
+ * if (error || !photoUrl) {
181
+ * // Fallback to Fluent UI Persona with initials
182
+ * return <Persona text="John Doe" size={PersonaSize.size72} />;
183
+ * }
184
+ *
185
+ * return <img src={photoUrl} alt="User" className="avatar-round" />;
186
+ * }
187
+ * ```
188
+ *
189
+ * @example Access raw blob for processing
190
+ * ```tsx
191
+ * function PhotoUploader() {
192
+ * const { photoBlob, photoUrl } = useSPFxUserPhoto();
193
+ *
194
+ * const handleUploadToAzure = async () => {
195
+ * if (!photoBlob) return;
196
+ *
197
+ * const formData = new FormData();
198
+ * formData.append('photo', photoBlob, 'profile.jpg');
199
+ *
200
+ * await fetch('/api/upload', {
201
+ * method: 'POST',
202
+ * body: formData
203
+ * });
204
+ * };
205
+ *
206
+ * return (
207
+ * <div>
208
+ * <img src={photoUrl} alt="Preview" />
209
+ * <button onClick={handleUploadToAzure}>Upload to Azure</button>
210
+ * </div>
211
+ * );
212
+ * }
213
+ * ```
214
+ */
215
+ export function useSPFxUserPhoto(options) {
216
+ var _this = this;
217
+ var graphClient = useSPFxMSGraphClient().client;
218
+ // Destructure options with defaults
219
+ var _a = options || {}, userId = _a.userId, email = _a.email, _b = _a.size, size = _b === void 0 ? '240x240' : _b, _c = _a.autoFetch, autoFetch = _c === void 0 ? true : _c;
220
+ // State management
221
+ var _d = useState(undefined), photoUrl = _d[0], setPhotoUrl = _d[1];
222
+ var _e = useState(undefined), photoBlob = _e[0], setPhotoBlob = _e[1];
223
+ var _f = useState(false), isLoading = _f[0], setIsLoading = _f[1];
224
+ var _g = useState(undefined), error = _g[0], setError = _g[1];
225
+ // Track component mounted state and current blob URL for cleanup
226
+ var isMounted = useRef(true);
227
+ var currentBlobUrl = useRef(undefined);
228
+ useEffect(function () {
229
+ isMounted.current = true;
230
+ return function () {
231
+ isMounted.current = false;
232
+ // Cleanup: revoke blob URL to prevent memory leaks
233
+ if (currentBlobUrl.current) {
234
+ URL.revokeObjectURL(currentBlobUrl.current);
235
+ currentBlobUrl.current = undefined;
236
+ }
237
+ };
238
+ }, []);
239
+ /**
240
+ * Build Graph API endpoint based on user identifier
241
+ */
242
+ var buildPhotoEndpoint = useCallback(function () {
243
+ // Determine base path
244
+ var basePath;
245
+ if (userId) {
246
+ // Specific user by ID
247
+ basePath = "/users/".concat(userId);
248
+ }
249
+ else if (email) {
250
+ // Specific user by email
251
+ basePath = "/users/".concat(email);
252
+ }
253
+ else {
254
+ // Current user
255
+ basePath = '/me';
256
+ }
257
+ // Append photo size endpoint
258
+ return "".concat(basePath, "/photos/").concat(size, "/$value");
259
+ }, [userId, email, size]);
260
+ /**
261
+ * Load photo from Microsoft Graph
262
+ */
263
+ var load = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
264
+ var err, endpoint, blob, blobUrl, err_1, error_1;
265
+ return __generator(this, function (_a) {
266
+ switch (_a.label) {
267
+ case 0:
268
+ if (!graphClient) {
269
+ err = new Error('MSGraphClient not available. Cannot load photo.');
270
+ console.error('[useSPFxUserPhoto]', err);
271
+ if (isMounted.current) {
272
+ setError(err);
273
+ }
274
+ return [2 /*return*/];
275
+ }
276
+ setIsLoading(true);
277
+ setError(undefined);
278
+ _a.label = 1;
279
+ case 1:
280
+ _a.trys.push([1, 3, 4, 5]);
281
+ endpoint = buildPhotoEndpoint();
282
+ return [4 /*yield*/, graphClient
283
+ .api(endpoint)
284
+ .get()];
285
+ case 2:
286
+ blob = _a.sent();
287
+ if (isMounted.current) {
288
+ // Revoke previous blob URL if exists
289
+ if (currentBlobUrl.current) {
290
+ URL.revokeObjectURL(currentBlobUrl.current);
291
+ }
292
+ blobUrl = URL.createObjectURL(blob);
293
+ currentBlobUrl.current = blobUrl;
294
+ setPhotoBlob(blob);
295
+ setPhotoUrl(blobUrl);
296
+ }
297
+ return [3 /*break*/, 5];
298
+ case 3:
299
+ err_1 = _a.sent();
300
+ if (isMounted.current) {
301
+ error_1 = err_1 instanceof Error ? err_1 : new Error(String(err_1));
302
+ // Enhanced error messages (ES5-compatible)
303
+ if (error_1.message.indexOf('404') !== -1) {
304
+ error_1.message = 'Photo not found. User may not have a profile photo.';
305
+ }
306
+ else if (error_1.message.indexOf('403') !== -1) {
307
+ error_1.message = 'Insufficient permissions to access photo. Check Graph API permissions.';
308
+ }
309
+ else if (error_1.message.indexOf('401') !== -1) {
310
+ error_1.message = 'Authentication failed. User may not be signed in.';
311
+ }
312
+ setError(error_1);
313
+ setPhotoUrl(undefined);
314
+ setPhotoBlob(undefined);
315
+ console.error('[useSPFxUserPhoto] Failed to load photo:', error_1);
316
+ }
317
+ return [3 /*break*/, 5];
318
+ case 4:
319
+ if (isMounted.current) {
320
+ setIsLoading(false);
321
+ }
322
+ return [7 /*endfinally*/];
323
+ case 5: return [2 /*return*/];
324
+ }
325
+ });
326
+ }); }, [graphClient, buildPhotoEndpoint]);
327
+ // Auto-fetch on mount if enabled
328
+ useEffect(function () {
329
+ if (autoFetch && graphClient) {
330
+ load().catch(function () {
331
+ // Error already handled in load() function
332
+ });
333
+ }
334
+ }, [autoFetch, graphClient, load]);
335
+ // Computed state: ready when photo loaded successfully
336
+ var isReady = !isLoading && !error && photoUrl !== undefined;
337
+ return {
338
+ photoUrl: photoUrl,
339
+ photoBlob: photoBlob,
340
+ isLoading: isLoading,
341
+ error: error,
342
+ reload: load,
343
+ isReady: isReady
344
+ };
345
+ }
346
+ //# sourceMappingURL=useSPFxUserPhoto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSPFxUserPhoto.js","sourceRoot":"","sources":["../../src/hooks/useSPFxUserPhoto.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './core';
2
+ export * from './hooks';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './core';
2
+ export * from './hooks';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ // Empty - no public utilities to export
2
+ // All utilities are internal and used only within the library
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,8DAA8D"}
@@ -0,0 +1,10 @@
1
+ import type { ContainerSize } from '../core/types';
2
+ /**
3
+ * Hook to observe element size changes using ResizeObserver
4
+ *
5
+ * @param element - DOM element to observe
6
+ * @param onResize - Callback when size changes
7
+ * @internal
8
+ */
9
+ export declare function useResizeObserver(element: HTMLElement | undefined, onResize: (size: ContainerSize | undefined) => void): void;
10
+ //# sourceMappingURL=resize-observer.internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-observer.internal.d.ts","sourceRoot":"","sources":["../../src/utils/resize-observer.internal.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,GAClD,IAAI,CAwBN"}
@@ -0,0 +1,34 @@
1
+ // resize-observer.ts
2
+ // Utility hook to observe element size changes
3
+ import { useEffect } from 'react';
4
+ /**
5
+ * Hook to observe element size changes using ResizeObserver
6
+ *
7
+ * @param element - DOM element to observe
8
+ * @param onResize - Callback when size changes
9
+ * @internal
10
+ */
11
+ export function useResizeObserver(element, onResize) {
12
+ useEffect(function () {
13
+ // If no element or ResizeObserver not supported, clear size
14
+ if (!element || typeof ResizeObserver === 'undefined') {
15
+ onResize(undefined);
16
+ return;
17
+ }
18
+ // Create ResizeObserver
19
+ var observer = new ResizeObserver(function (entries) {
20
+ for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
21
+ var entry = entries_1[_i];
22
+ var _a = entry.contentRect, width = _a.width, height = _a.height;
23
+ onResize({ width: width, height: height });
24
+ }
25
+ });
26
+ // Start observing
27
+ observer.observe(element);
28
+ // Cleanup on unmount
29
+ return function () {
30
+ observer.disconnect();
31
+ };
32
+ }, [element, onResize]);
33
+ }
34
+ //# sourceMappingURL=resize-observer.internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-observer.internal.js","sourceRoot":"","sources":["../../src/utils/resize-observer.internal.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,+CAA+C;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAgC,EAChC,QAAmD;IAEnD,SAAS,CAAC;QACR,4DAA4D;QAC5D,IAAI,CAAC,OAAO,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;YACtD,QAAQ,CAAC,SAAS,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QAED,wBAAwB;QACxB,IAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,UAAC,OAAO;YAC1C,KAAoB,UAAO,EAAP,mBAAO,EAAP,qBAAO,EAAP,IAAO,EAAE,CAAC;gBAAzB,IAAM,KAAK,gBAAA;gBACR,IAAA,KAAoB,KAAK,CAAC,WAAW,EAAnC,KAAK,WAAA,EAAE,MAAM,YAAsB,CAAC;gBAC5C,QAAQ,CAAC,EAAE,KAAK,OAAA,EAAE,MAAM,QAAA,EAAE,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,kBAAkB;QAClB,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1B,qBAAqB;QACrB,OAAO;YACL,QAAQ,CAAC,UAAU,EAAE,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { IReadonlyTheme } from '@microsoft/sp-component-base';
2
+ /**
3
+ * Hook to subscribe to SPFx theme changes
4
+ * Automatically updates the provided setter when theme changes
5
+ *
6
+ * @param spfxContext - SPFx context object
7
+ * @param setTheme - Setter function to update theme state
8
+ * @internal
9
+ */
10
+ export declare function useThemeSubscription(spfxContext: unknown, setTheme: (theme: IReadonlyTheme | undefined) => void): void;
11
+ //# sourceMappingURL=theme-subscription.internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-subscription.internal.d.ts","sourceRoot":"","sources":["../../src/utils/theme-subscription.internal.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAuBnE;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,OAAO,EACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,KAAK,IAAI,GACpD,IAAI,CAmCN"}
@@ -0,0 +1,58 @@
1
+ // theme-subscription.ts
2
+ // Utility hook to subscribe to SPFx theme changes
3
+ import { useEffect } from 'react';
4
+ import { ThemeProvider } from '@microsoft/sp-component-base';
5
+ /**
6
+ * Extract ThemeProvider from SPFx context
7
+ * Works with any SPFx context type (WebPart, ApplicationCustomizer, etc.)
8
+ * @internal
9
+ */
10
+ function getThemeProvider(spfxContext) {
11
+ var ctx = spfxContext;
12
+ if (!ctx.serviceScope) {
13
+ throw new Error('SPFx context does not have serviceScope');
14
+ }
15
+ // Consume ThemeProvider from service scope
16
+ // ServiceScope.consume() is type-safe with ServiceKey<T>
17
+ return ctx.serviceScope.consume(ThemeProvider.serviceKey);
18
+ }
19
+ /**
20
+ * Hook to subscribe to SPFx theme changes
21
+ * Automatically updates the provided setter when theme changes
22
+ *
23
+ * @param spfxContext - SPFx context object
24
+ * @param setTheme - Setter function to update theme state
25
+ * @internal
26
+ */
27
+ export function useThemeSubscription(spfxContext, setTheme) {
28
+ useEffect(function () {
29
+ var themeProvider = getThemeProvider(spfxContext);
30
+ // Get initial theme
31
+ var initialTheme = themeProvider.tryGetTheme();
32
+ if (initialTheme) {
33
+ setTheme(initialTheme);
34
+ }
35
+ // Create event handler
36
+ var handler = function (args) {
37
+ setTheme(args.theme);
38
+ };
39
+ // Create observer object for SPFx event system
40
+ var observer = {
41
+ instanceId: 'theme-subscription',
42
+ componentId: 'theme-subscription',
43
+ isDisposed: false,
44
+ dispose: function () {
45
+ // Cleanup handled in useEffect return
46
+ },
47
+ update: handler,
48
+ };
49
+ // Subscribe to theme changes
50
+ themeProvider.themeChangedEvent.add(observer, handler);
51
+ // Cleanup on unmount
52
+ return function () {
53
+ observer.isDisposed = true;
54
+ themeProvider.themeChangedEvent.remove(observer, handler);
55
+ };
56
+ }, [spfxContext, setTheme]);
57
+ }
58
+ //# sourceMappingURL=theme-subscription.internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-subscription.internal.js","sourceRoot":"","sources":["../../src/utils/theme-subscription.internal.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,kDAAkD;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,WAAoB;IAC5C,IAAM,GAAG,GAAG,WAEX,CAAC;IAEF,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,2CAA2C;IAC3C,yDAAyD;IACzD,OAAO,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,QAAqD;IAErD,SAAS,CAAC;QACR,IAAM,aAAa,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAEpD,oBAAoB;QACpB,IAAM,YAAY,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;QACjD,IAAI,YAAY,EAAE,CAAC;YACjB,QAAQ,CAAC,YAAY,CAAC,CAAC;QACzB,CAAC;QAED,uBAAuB;QACvB,IAAM,OAAO,GAAG,UAAC,IAAgC;YAC/C,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC;QAEF,+CAA+C;QAC/C,IAAM,QAAQ,GAAG;YACf,UAAU,EAAE,oBAAoB;YAChC,WAAW,EAAE,oBAAoB;YACjC,UAAU,EAAE,KAAK;YACjB,OAAO,EAAE;gBACP,sCAAsC;YACxC,CAAC;YACD,MAAM,EAAE,OAAO;SAChB,CAAC;QAEF,6BAA6B;QAC7B,aAAa,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEvD,qBAAqB;QACrB,OAAO;YACL,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC;YAC3B,aAAa,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5D,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
2
+ import type { BaseApplicationCustomizer } from '@microsoft/sp-application-base';
3
+ import type { BaseListViewCommandSet, BaseFieldCustomizer } from '@microsoft/sp-listview-extensibility';
4
+ import type { SPFxComponent, HostKind } from '../core/types';
5
+ /**
6
+ * Type guard: Check if instance is a WebPart
7
+ * Uses duck typing - checks for WebPart-specific properties
8
+ * @internal
9
+ */
10
+ export declare function isWebPart<TProps extends {} = {}>(instance: unknown): instance is BaseClientSideWebPart<TProps>;
11
+ /**
12
+ * Type guard: Check if instance is an ApplicationCustomizer
13
+ * Uses duck typing - checks for ApplicationCustomizer-specific properties
14
+ * @internal
15
+ */
16
+ export declare function isApplicationCustomizer<TProps extends {} = {}>(instance: unknown): instance is BaseApplicationCustomizer<TProps>;
17
+ /**
18
+ * Type guard: Check if instance is a ListViewCommandSet
19
+ * Uses duck typing - checks for CommandSet-specific properties
20
+ * @internal
21
+ */
22
+ export declare function isListViewCommandSet<TProps extends {} = {}>(instance: unknown): instance is BaseListViewCommandSet<TProps>;
23
+ /**
24
+ * Type guard: Check if instance is a FieldCustomizer
25
+ * Uses duck typing - checks for FieldCustomizer-specific properties
26
+ * @internal
27
+ */
28
+ export declare function isFieldCustomizer<TProps extends {} = {}>(instance: unknown): instance is BaseFieldCustomizer<TProps>;
29
+ /**
30
+ * Detect the kind of SPFx component from an instance
31
+ * Throws if unable to detect
32
+ * @internal
33
+ */
34
+ export declare function detectComponentKind<TProps extends {} = {}>(instance: SPFxComponent<TProps>): HostKind;
35
+ //# sourceMappingURL=type-guards.internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-guards.internal.d.ts","sourceRoot":"","sources":["../../src/utils/type-guards.internal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AACxG,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACT,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAS,EAAE,GAAG,EAAE,EAC9C,QAAQ,EAAE,OAAO,GAChB,QAAQ,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAa3C;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,SAAS,EAAE,GAAG,EAAE,EAC5D,QAAQ,EAAE,OAAO,GAChB,QAAQ,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAgB/C;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,EAAE,GAAG,EAAE,EACzD,QAAQ,EAAE,OAAO,GAChB,QAAQ,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAa5C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,EAAE,GAAG,EAAE,EACtD,QAAQ,EAAE,OAAO,GAChB,QAAQ,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAiBzC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,SAAS,EAAE,GAAG,EAAE,EACxD,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAC9B,QAAQ,CAUV"}
@@ -0,0 +1,88 @@
1
+ // type-guards.ts
2
+ // Type guards for SPFx component detection using structural typing (duck typing)
3
+ /**
4
+ * Type guard: Check if instance is a WebPart
5
+ * Uses duck typing - checks for WebPart-specific properties
6
+ * @internal
7
+ */
8
+ export function isWebPart(instance) {
9
+ if (!instance || typeof instance !== 'object')
10
+ return false;
11
+ var obj = instance;
12
+ return ('displayMode' in obj &&
13
+ 'domElement' in obj &&
14
+ 'render' in obj &&
15
+ typeof obj.render === 'function' &&
16
+ 'context' in obj &&
17
+ 'properties' in obj);
18
+ }
19
+ /**
20
+ * Type guard: Check if instance is an ApplicationCustomizer
21
+ * Uses duck typing - checks for ApplicationCustomizer-specific properties
22
+ * @internal
23
+ */
24
+ export function isApplicationCustomizer(instance) {
25
+ if (!instance || typeof instance !== 'object')
26
+ return false;
27
+ var obj = instance;
28
+ if (!('context' in obj) || !obj.context || typeof obj.context !== 'object') {
29
+ return false;
30
+ }
31
+ var context = obj.context;
32
+ return ('placeholderProvider' in context &&
33
+ 'properties' in obj &&
34
+ !('displayMode' in obj) // Not a WebPart
35
+ );
36
+ }
37
+ /**
38
+ * Type guard: Check if instance is a ListViewCommandSet
39
+ * Uses duck typing - checks for CommandSet-specific properties
40
+ * @internal
41
+ */
42
+ export function isListViewCommandSet(instance) {
43
+ if (!instance || typeof instance !== 'object')
44
+ return false;
45
+ var obj = instance;
46
+ return ('onExecute' in obj &&
47
+ typeof obj.onExecute === 'function' &&
48
+ 'tryGetCommand' in obj &&
49
+ typeof obj.tryGetCommand === 'function' &&
50
+ 'context' in obj &&
51
+ 'properties' in obj);
52
+ }
53
+ /**
54
+ * Type guard: Check if instance is a FieldCustomizer
55
+ * Uses duck typing - checks for FieldCustomizer-specific properties
56
+ * @internal
57
+ */
58
+ export function isFieldCustomizer(instance) {
59
+ if (!instance || typeof instance !== 'object')
60
+ return false;
61
+ var obj = instance;
62
+ if (!('context' in obj) || !obj.context || typeof obj.context !== 'object') {
63
+ return false;
64
+ }
65
+ var context = obj.context;
66
+ return ('field' in context &&
67
+ 'onRenderCell' in obj &&
68
+ typeof obj.onRenderCell === 'function' &&
69
+ 'properties' in obj);
70
+ }
71
+ /**
72
+ * Detect the kind of SPFx component from an instance
73
+ * Throws if unable to detect
74
+ * @internal
75
+ */
76
+ export function detectComponentKind(instance) {
77
+ if (isWebPart(instance))
78
+ return 'WebPart';
79
+ if (isApplicationCustomizer(instance))
80
+ return 'AppCustomizer';
81
+ if (isListViewCommandSet(instance))
82
+ return 'CommandSet';
83
+ if (isFieldCustomizer(instance))
84
+ return 'FieldCustomizer';
85
+ throw new Error('[SPFxProvider] Unable to detect SPFx component type. ' +
86
+ 'Instance must be a WebPart, ApplicationCustomizer, CommandSet, or FieldCustomizer.');
87
+ }
88
+ //# sourceMappingURL=type-guards.internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-guards.internal.js","sourceRoot":"","sources":["../../src/utils/type-guards.internal.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,iFAAiF;AAUjF;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,QAAiB;IAEjB,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE5D,IAAM,GAAG,GAAG,QAAmC,CAAC;IAEhD,OAAO,CACL,aAAa,IAAI,GAAG;QACpB,YAAY,IAAI,GAAG;QACnB,QAAQ,IAAI,GAAG;QACf,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU;QAChC,SAAS,IAAI,GAAG;QAChB,YAAY,IAAI,GAAG,CACpB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAAiB;IAEjB,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE5D,IAAM,GAAG,GAAG,QAAmC,CAAC;IAEhD,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAM,OAAO,GAAG,GAAG,CAAC,OAAkC,CAAC;IAEvD,OAAO,CACL,qBAAqB,IAAI,OAAO;QAChC,YAAY,IAAI,GAAG;QACnB,CAAC,CAAC,aAAa,IAAI,GAAG,CAAC,CAAC,gBAAgB;KACzC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAiB;IAEjB,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE5D,IAAM,GAAG,GAAG,QAAmC,CAAC;IAEhD,OAAO,CACL,WAAW,IAAI,GAAG;QAClB,OAAO,GAAG,CAAC,SAAS,KAAK,UAAU;QACnC,eAAe,IAAI,GAAG;QACtB,OAAO,GAAG,CAAC,aAAa,KAAK,UAAU;QACvC,SAAS,IAAI,GAAG;QAChB,YAAY,IAAI,GAAG,CACpB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAiB;IAEjB,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE5D,IAAM,GAAG,GAAG,QAAmC,CAAC;IAEhD,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAM,OAAO,GAAG,GAAG,CAAC,OAAkC,CAAC;IAEvD,OAAO,CACL,OAAO,IAAI,OAAO;QAClB,cAAc,IAAI,GAAG;QACrB,OAAO,GAAG,CAAC,YAAY,KAAK,UAAU;QACtC,YAAY,IAAI,GAAG,CACpB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA+B;IAE/B,IAAI,SAAS,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,uBAAuB,CAAC,QAAQ,CAAC;QAAE,OAAO,eAAe,CAAC;IAC9D,IAAI,oBAAoB,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC;IACxD,IAAI,iBAAiB,CAAC,QAAQ,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAE1D,MAAM,IAAI,KAAK,CACb,uDAAuD;QACvD,oFAAoF,CACrF,CAAC;AACJ,CAAC"}