@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.
- package/LICENSE +21 -0
- package/README.md +2012 -0
- package/lib/core/atoms.internal.d.ts +53 -0
- package/lib/core/atoms.internal.d.ts.map +1 -0
- package/lib/core/atoms.internal.js +35 -0
- package/lib/core/atoms.internal.js.map +1 -0
- package/lib/core/context.internal.d.ts +23 -0
- package/lib/core/context.internal.d.ts.map +1 -0
- package/lib/core/context.internal.js +34 -0
- package/lib/core/context.internal.js.map +1 -0
- package/lib/core/index.d.ts +6 -0
- package/lib/core/index.d.ts.map +1 -0
- package/lib/core/index.js +6 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/provider-application-customizer.d.ts +57 -0
- package/lib/core/provider-application-customizer.d.ts.map +1 -0
- package/lib/core/provider-application-customizer.js +45 -0
- package/lib/core/provider-application-customizer.js.map +1 -0
- package/lib/core/provider-base.internal.d.ts +20 -0
- package/lib/core/provider-base.internal.d.ts.map +1 -0
- package/lib/core/provider-base.internal.js +126 -0
- package/lib/core/provider-base.internal.js.map +1 -0
- package/lib/core/provider-field-customizer.d.ts +58 -0
- package/lib/core/provider-field-customizer.d.ts.map +1 -0
- package/lib/core/provider-field-customizer.js +46 -0
- package/lib/core/provider-field-customizer.js.map +1 -0
- package/lib/core/provider-listview-commandset.d.ts +60 -0
- package/lib/core/provider-listview-commandset.d.ts.map +1 -0
- package/lib/core/provider-listview-commandset.js +48 -0
- package/lib/core/provider-listview-commandset.js.map +1 -0
- package/lib/core/provider-webpart.d.ts +48 -0
- package/lib/core/provider-webpart.d.ts.map +1 -0
- package/lib/core/provider-webpart.js +36 -0
- package/lib/core/provider-webpart.js.map +1 -0
- package/lib/core/types.d.ts +84 -0
- package/lib/core/types.d.ts.map +1 -0
- package/lib/core/types.js +4 -0
- package/lib/core/types.js.map +1 -0
- package/lib/hooks/index.d.ts +34 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/index.js +34 -0
- package/lib/hooks/index.js.map +1 -0
- package/lib/hooks/useSPFxAadHttpClient.d.ts +231 -0
- package/lib/hooks/useSPFxAadHttpClient.d.ts.map +1 -0
- package/lib/hooks/useSPFxAadHttpClient.js +299 -0
- package/lib/hooks/useSPFxAadHttpClient.js.map +1 -0
- package/lib/hooks/useSPFxContainerInfo.d.ts +41 -0
- package/lib/hooks/useSPFxContainerInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxContainerInfo.js +47 -0
- package/lib/hooks/useSPFxContainerInfo.js.map +1 -0
- package/lib/hooks/useSPFxContainerSize.d.ts +119 -0
- package/lib/hooks/useSPFxContainerSize.d.ts.map +1 -0
- package/lib/hooks/useSPFxContainerSize.js +150 -0
- package/lib/hooks/useSPFxContainerSize.js.map +1 -0
- package/lib/hooks/useSPFxContext.d.ts +14 -0
- package/lib/hooks/useSPFxContext.d.ts.map +1 -0
- package/lib/hooks/useSPFxContext.js +16 -0
- package/lib/hooks/useSPFxContext.js.map +1 -0
- package/lib/hooks/useSPFxCorrelationInfo.d.ts +51 -0
- package/lib/hooks/useSPFxCorrelationInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxCorrelationInfo.js +58 -0
- package/lib/hooks/useSPFxCorrelationInfo.js.map +1 -0
- package/lib/hooks/useSPFxCrossSitePermissions.d.ts +81 -0
- package/lib/hooks/useSPFxCrossSitePermissions.d.ts.map +1 -0
- package/lib/hooks/useSPFxCrossSitePermissions.js +132 -0
- package/lib/hooks/useSPFxCrossSitePermissions.js.map +1 -0
- package/lib/hooks/useSPFxDisplayMode.d.ts +61 -0
- package/lib/hooks/useSPFxDisplayMode.d.ts.map +1 -0
- package/lib/hooks/useSPFxDisplayMode.js +69 -0
- package/lib/hooks/useSPFxDisplayMode.js.map +1 -0
- package/lib/hooks/useSPFxEnvironmentInfo.d.ts +63 -0
- package/lib/hooks/useSPFxEnvironmentInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxEnvironmentInfo.js +91 -0
- package/lib/hooks/useSPFxEnvironmentInfo.js.map +1 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts +105 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.js +136 -0
- package/lib/hooks/useSPFxFluent9ThemeInfo.js.map +1 -0
- package/lib/hooks/useSPFxHubSiteInfo.d.ts +80 -0
- package/lib/hooks/useSPFxHubSiteInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxHubSiteInfo.js +127 -0
- package/lib/hooks/useSPFxHubSiteInfo.js.map +1 -0
- package/lib/hooks/useSPFxInstanceInfo.d.ts +41 -0
- package/lib/hooks/useSPFxInstanceInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxInstanceInfo.js +40 -0
- package/lib/hooks/useSPFxInstanceInfo.js.map +1 -0
- package/lib/hooks/useSPFxListInfo.d.ts +64 -0
- package/lib/hooks/useSPFxListInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxListInfo.js +70 -0
- package/lib/hooks/useSPFxListInfo.js.map +1 -0
- package/lib/hooks/useSPFxLocaleInfo.d.ts +123 -0
- package/lib/hooks/useSPFxLocaleInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxLocaleInfo.js +109 -0
- package/lib/hooks/useSPFxLocaleInfo.js.map +1 -0
- package/lib/hooks/useSPFxLogger.d.ts +108 -0
- package/lib/hooks/useSPFxLogger.d.ts.map +1 -0
- package/lib/hooks/useSPFxLogger.js +117 -0
- package/lib/hooks/useSPFxLogger.js.map +1 -0
- package/lib/hooks/useSPFxMSGraphClient.d.ts +200 -0
- package/lib/hooks/useSPFxMSGraphClient.d.ts.map +1 -0
- package/lib/hooks/useSPFxMSGraphClient.js +264 -0
- package/lib/hooks/useSPFxMSGraphClient.js.map +1 -0
- package/lib/hooks/useSPFxOneDriveAppData.d.ts +264 -0
- package/lib/hooks/useSPFxOneDriveAppData.d.ts.map +1 -0
- package/lib/hooks/useSPFxOneDriveAppData.js +395 -0
- package/lib/hooks/useSPFxOneDriveAppData.js.map +1 -0
- package/lib/hooks/useSPFxPageContext.d.ts +37 -0
- package/lib/hooks/useSPFxPageContext.d.ts.map +1 -0
- package/lib/hooks/useSPFxPageContext.js +49 -0
- package/lib/hooks/useSPFxPageContext.js.map +1 -0
- package/lib/hooks/useSPFxPageType.d.ts +82 -0
- package/lib/hooks/useSPFxPageType.d.ts.map +1 -0
- package/lib/hooks/useSPFxPageType.js +137 -0
- package/lib/hooks/useSPFxPageType.js.map +1 -0
- package/lib/hooks/useSPFxPerformance.d.ts +72 -0
- package/lib/hooks/useSPFxPerformance.d.ts.map +1 -0
- package/lib/hooks/useSPFxPerformance.js +167 -0
- package/lib/hooks/useSPFxPerformance.js.map +1 -0
- package/lib/hooks/useSPFxPermissions.d.ts +61 -0
- package/lib/hooks/useSPFxPermissions.d.ts.map +1 -0
- package/lib/hooks/useSPFxPermissions.js +73 -0
- package/lib/hooks/useSPFxPermissions.js.map +1 -0
- package/lib/hooks/useSPFxPnP.d.ts +539 -0
- package/lib/hooks/useSPFxPnP.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnP.js +533 -0
- package/lib/hooks/useSPFxPnP.js.map +1 -0
- package/lib/hooks/useSPFxPnPContext.d.ts +290 -0
- package/lib/hooks/useSPFxPnPContext.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnPContext.js +340 -0
- package/lib/hooks/useSPFxPnPContext.js.map +1 -0
- package/lib/hooks/useSPFxPnPList.d.ts +545 -0
- package/lib/hooks/useSPFxPnPList.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnPList.js +906 -0
- package/lib/hooks/useSPFxPnPList.js.map +1 -0
- package/lib/hooks/useSPFxPnPSearch.d.ts +540 -0
- package/lib/hooks/useSPFxPnPSearch.d.ts.map +1 -0
- package/lib/hooks/useSPFxPnPSearch.js +672 -0
- package/lib/hooks/useSPFxPnPSearch.js.map +1 -0
- package/lib/hooks/useSPFxProperties.d.ts +80 -0
- package/lib/hooks/useSPFxProperties.d.ts.map +1 -0
- package/lib/hooks/useSPFxProperties.js +95 -0
- package/lib/hooks/useSPFxProperties.js.map +1 -0
- package/lib/hooks/useSPFxSPHttpClient.d.ts +218 -0
- package/lib/hooks/useSPFxSPHttpClient.d.ts.map +1 -0
- package/lib/hooks/useSPFxSPHttpClient.js +287 -0
- package/lib/hooks/useSPFxSPHttpClient.js.map +1 -0
- package/lib/hooks/useSPFxServiceScope.d.ts +107 -0
- package/lib/hooks/useSPFxServiceScope.d.ts.map +1 -0
- package/lib/hooks/useSPFxServiceScope.js +105 -0
- package/lib/hooks/useSPFxServiceScope.js.map +1 -0
- package/lib/hooks/useSPFxSiteInfo.d.ts +116 -0
- package/lib/hooks/useSPFxSiteInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxSiteInfo.js +109 -0
- package/lib/hooks/useSPFxSiteInfo.js.map +1 -0
- package/lib/hooks/useSPFxStorage.d.ts +81 -0
- package/lib/hooks/useSPFxStorage.d.ts.map +1 -0
- package/lib/hooks/useSPFxStorage.js +140 -0
- package/lib/hooks/useSPFxStorage.js.map +1 -0
- package/lib/hooks/useSPFxTeams.d.ts +63 -0
- package/lib/hooks/useSPFxTeams.d.ts.map +1 -0
- package/lib/hooks/useSPFxTeams.js +198 -0
- package/lib/hooks/useSPFxTeams.js.map +1 -0
- package/lib/hooks/useSPFxTenantProperty.d.ts +389 -0
- package/lib/hooks/useSPFxTenantProperty.d.ts.map +1 -0
- package/lib/hooks/useSPFxTenantProperty.js +683 -0
- package/lib/hooks/useSPFxTenantProperty.js.map +1 -0
- package/lib/hooks/useSPFxThemeInfo.d.ts +27 -0
- package/lib/hooks/useSPFxThemeInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxThemeInfo.js +33 -0
- package/lib/hooks/useSPFxThemeInfo.js.map +1 -0
- package/lib/hooks/useSPFxUserInfo.d.ts +47 -0
- package/lib/hooks/useSPFxUserInfo.d.ts.map +1 -0
- package/lib/hooks/useSPFxUserInfo.js +47 -0
- package/lib/hooks/useSPFxUserInfo.js.map +1 -0
- package/lib/hooks/useSPFxUserPhoto.d.ts +270 -0
- package/lib/hooks/useSPFxUserPhoto.d.ts.map +1 -0
- package/lib/hooks/useSPFxUserPhoto.js +346 -0
- package/lib/hooks/useSPFxUserPhoto.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +3 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/resize-observer.internal.d.ts +10 -0
- package/lib/utils/resize-observer.internal.d.ts.map +1 -0
- package/lib/utils/resize-observer.internal.js +34 -0
- package/lib/utils/resize-observer.internal.js.map +1 -0
- package/lib/utils/theme-subscription.internal.d.ts +11 -0
- package/lib/utils/theme-subscription.internal.d.ts.map +1 -0
- package/lib/utils/theme-subscription.internal.js +58 -0
- package/lib/utils/theme-subscription.internal.js.map +1 -0
- package/lib/utils/type-guards.internal.d.ts +35 -0
- package/lib/utils/type-guards.internal.d.ts.map +1 -0
- package/lib/utils/type-guards.internal.js +88 -0
- package/lib/utils/type-guards.internal.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts +13 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js +67 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/SpFxReactToolkitTestWebPart.manifest.json +21 -0
- package/lib/webparts/spFxReactToolkitTest/assets/welcome-dark.png +0 -0
- package/lib/webparts/spFxReactToolkitTest/assets/welcome-light.png +0 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts +8 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js +2 -0
- package/lib/webparts/spFxReactToolkitTest/components/ISpFxReactToolkitTestProps.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts +8 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js +1351 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.css +2 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts +18 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.d.ts.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js +19 -0
- package/lib/webparts/spFxReactToolkitTest/components/SpFxReactToolkitTest.module.scss.js.map +1 -0
- package/lib/webparts/spFxReactToolkitTest/loc/en-us.js +16 -0
- 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":"AAAA,sBAAsB;AACtB,oDAAoD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEpD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAoH9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6KG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAA8B;IADhC,iBA4IC;IAzIS,IAAQ,WAAW,GAAK,oBAAoB,EAAE,OAA3B,CAA4B;IAEvD,oCAAoC;IAC9B,IAAA,KAKF,OAAO,IAAI,EAAE,EAJf,MAAM,YAAA,EACN,KAAK,WAAA,EACL,YAAgB,EAAhB,IAAI,mBAAG,SAAS,KAAA,EAChB,iBAAgB,EAAhB,SAAS,mBAAG,IAAI,KACD,CAAC;IAElB,mBAAmB;IACb,IAAA,KAA0B,QAAQ,CAAqB,SAAS,CAAC,EAAhE,QAAQ,QAAA,EAAE,WAAW,QAA2C,CAAC;IAClE,IAAA,KAA4B,QAAQ,CAAmB,SAAS,CAAC,EAAhE,SAAS,QAAA,EAAE,YAAY,QAAyC,CAAC;IAClE,IAAA,KAA4B,QAAQ,CAAU,KAAK,CAAC,EAAnD,SAAS,QAAA,EAAE,YAAY,QAA4B,CAAC;IACrD,IAAA,KAAoB,QAAQ,CAAoB,SAAS,CAAC,EAAzD,KAAK,QAAA,EAAE,QAAQ,QAA0C,CAAC;IAEjE,iEAAiE;IACjE,IAAM,SAAS,GAAG,MAAM,CAAU,IAAI,CAAC,CAAC;IACxC,IAAM,cAAc,GAAG,MAAM,CAAqB,SAAS,CAAC,CAAC;IAE7D,SAAS,CAAC;QACR,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,OAAO;YACL,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC;YAC1B,mDAAmD;YACnD,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;gBAC3B,GAAG,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBAC5C,cAAc,CAAC,OAAO,GAAG,SAAS,CAAC;YACrC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP;;OAEG;IACH,IAAM,kBAAkB,GAAG,WAAW,CAAC;QACrC,sBAAsB;QACtB,IAAI,QAAgB,CAAC;QAErB,IAAI,MAAM,EAAE,CAAC;YACX,sBAAsB;YACtB,QAAQ,GAAG,iBAAU,MAAM,CAAE,CAAC;QAChC,CAAC;aAAM,IAAI,KAAK,EAAE,CAAC;YACjB,yBAAyB;YACzB,QAAQ,GAAG,iBAAU,KAAK,CAAE,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,eAAe;YACf,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,6BAA6B;QAC7B,OAAO,UAAG,QAAQ,qBAAW,IAAI,YAAS,CAAC;IAC7C,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAE1B;;OAEG;IACH,IAAM,IAAI,GAAG,WAAW,CAAC;;;;;oBACvB,IAAI,CAAC,WAAW,EAAE,CAAC;wBACX,GAAG,GAAG,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;wBACzE,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;wBAEzC,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;4BACtB,QAAQ,CAAC,GAAG,CAAC,CAAC;wBAChB,CAAC;wBACD,sBAAO;oBACT,CAAC;oBAED,YAAY,CAAC,IAAI,CAAC,CAAC;oBACnB,QAAQ,CAAC,SAAS,CAAC,CAAC;;;;oBAGZ,QAAQ,GAAG,kBAAkB,EAAE,CAAC;oBAGnB,qBAAM,WAAW;6BACjC,GAAG,CAAC,QAAQ,CAAC;6BACb,GAAG,EAAE,EAAA;;oBAFF,IAAI,GAAS,SAEX;oBAER,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtB,qCAAqC;wBACrC,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;4BAC3B,GAAG,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;wBAC9C,CAAC;wBAGK,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;wBAC1C,cAAc,CAAC,OAAO,GAAG,OAAO,CAAC;wBAEjC,YAAY,CAAC,IAAI,CAAC,CAAC;wBACnB,WAAW,CAAC,OAAO,CAAC,CAAC;oBACvB,CAAC;;;;oBAED,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBAChB,UAAQ,KAAG,YAAY,KAAK,CAAC,CAAC,CAAC,KAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAG,CAAC,CAAC,CAAC;wBAElE,2CAA2C;wBAC3C,IAAI,OAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BACxC,OAAK,CAAC,OAAO,GAAG,qDAAqD,CAAC;wBACxE,CAAC;6BAAM,IAAI,OAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BAC/C,OAAK,CAAC,OAAO,GAAG,wEAAwE,CAAC;wBAC3F,CAAC;6BAAM,IAAI,OAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BAC/C,OAAK,CAAC,OAAO,GAAG,mDAAmD,CAAC;wBACtE,CAAC;wBAED,QAAQ,CAAC,OAAK,CAAC,CAAC;wBAChB,WAAW,CAAC,SAAS,CAAC,CAAC;wBACvB,YAAY,CAAC,SAAS,CAAC,CAAC;wBACxB,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,OAAK,CAAC,CAAC;oBACnE,CAAC;;;oBAED,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;wBACtB,YAAY,CAAC,KAAK,CAAC,CAAC;oBACtB,CAAC;;;;;SAEJ,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAEtC,iCAAiC;IACjC,SAAS,CAAC;QACR,IAAI,SAAS,IAAI,WAAW,EAAE,CAAC;YAC7B,IAAI,EAAE,CAAC,KAAK,CAAC;gBACX,2CAA2C;YAC7C,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;IAEnC,uDAAuD;IACvD,IAAM,OAAO,GAAG,CAAC,SAAS,IAAI,CAAC,KAAK,IAAI,QAAQ,KAAK,SAAS,CAAC;IAE/D,OAAO;QACL,QAAQ,UAAA;QACR,SAAS,WAAA;QACT,SAAS,WAAA;QACT,KAAK,OAAA;QACL,MAAM,EAAE,IAAI;QACZ,OAAO,SAAA;KACR,CAAC;AACJ,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -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
package/lib/index.js.map
ADDED
|
@@ -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 @@
|
|
|
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"}
|