Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Only for testing purpose don't review]FHL tree shaking example #2225

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/teams-test-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import AuthenticationAPIs from './components/AuthenticationAPIs';
import BarCodeAPIs from './components/BarCodeAPIs';
import CalendarAPIs from './components/CalendarAPIs';
import CallAPIs from './components/CallAPIs';
import ClipboardAPIs from './components/Clipboard';
// import ClipboardAPIs from './components/Clipboard';
import CustomAPIs from './components/Custom';
import DialogAPIs from './components/DialogAPIs';
import DialogCardAPIs from './components/DialogCardAPIs';
Expand Down Expand Up @@ -136,7 +136,7 @@ const App = (): ReactElement => {
<CalendarAPIs />
<CallAPIs />
<ChatAPIs />
<ClipboardAPIs />
{/* <ClipboardAPIs /> */}
<CustomAPIs />
<DialogAPIs />
<DialogCardAPIs />
Expand Down
192 changes: 96 additions & 96 deletions apps/teams-test-app/src/components/Clipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,104 +1,104 @@
import { clipboard } from '@microsoft/teams-js';
import React from 'react';
// import { read } from '@microsoft/teams-js';
// import React from 'react';

import { noHostSdkMsg } from '../App';
import { ApiWithoutInput, ApiWithTextInput } from './utils';
import { ModuleWrapper } from './utils/ModuleWrapper';
// import { noHostSdkMsg } from '../App';
// import { ApiWithoutInput, ApiWithTextInput } from './utils';
// import { ModuleWrapper } from './utils/ModuleWrapper';

const image = document.createElement('img');
image.setAttribute('id', 'clipboardImage');
// const image = document.createElement('img');
// image.setAttribute('id', 'clipboardImage');

const CheckCallCapability = (): React.ReactElement =>
ApiWithoutInput({
name: 'checkCapabilityClipboard',
title: 'Check Capability Clipboard',
onClick: async () => `Clipboard module ${clipboard.isSupported() ? 'is' : 'is not'} supported`,
});
// const CheckCallCapability = (): React.ReactElement =>
// ApiWithoutInput({
// name: 'checkCapabilityClipboard',
// title: 'Check Capability Clipboard',
// onClick: async () => `Clipboard module ${clipboard.isSupported() ? 'is' : 'is not'} supported`,
// });

const CopyText = (): React.ReactElement =>
ApiWithTextInput<string>({
name: 'copyText',
title: 'Copy',
onClick: {
validateInput: (input) => {
if (!input) {
throw "String can't be empty";
}
},
submit: async (text) => {
const blob = new Blob([text], { type: 'text/html' });
await clipboard.write(blob);
return JSON.stringify(true);
},
},
defaultInput: '"copy this test"',
});
// const CopyText = (): React.ReactElement =>
// ApiWithTextInput<string>({
// name: 'copyText',
// title: 'Copy',
// onClick: {
// validateInput: (input) => {
// if (!input) {
// throw "String can't be empty";
// }
// },
// submit: async (text) => {
// const blob = new Blob([text], { type: 'text/html' });
// await clipboard.write(blob);
// return JSON.stringify(true);
// },
// },
// defaultInput: '"copy this test"',
// });

const CopyImage = (): React.ReactElement =>
ApiWithTextInput({
name: 'copyImage',
title: 'Copy Image',
onClick: {
validateInput: (input) => {
if (!input) {
throw "mimeType can't be empty";
}
},
submit: async (mimeType) => {
const byteCharacters = atob(
'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
);
const byteArray = new Uint8Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteArray[i] = byteCharacters.charCodeAt(i);
}
await clipboard.write(new Blob([byteArray], { type: mimeType as string }));
return JSON.stringify(true);
},
},
defaultInput: '"image/jpeg"',
});
// const CopyImage = (): React.ReactElement =>
// ApiWithTextInput({
// name: 'copyImage',
// title: 'Copy Image',
// onClick: {
// validateInput: (input) => {
// if (!input) {
// throw "mimeType can't be empty";
// }
// },
// submit: async (mimeType) => {
// const byteCharacters = atob(
// 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
// );
// const byteArray = new Uint8Array(byteCharacters.length);
// for (let i = 0; i < byteCharacters.length; i++) {
// byteArray[i] = byteCharacters.charCodeAt(i);
// }
// await clipboard.write(new Blob([byteArray], { type: mimeType as string }));
// return JSON.stringify(true);
// },
// },
// defaultInput: '"image/jpeg"',
// });

const pasteHelper = (blob: Blob, setResult: (result: string) => void): void => {
const reader = new FileReader();
reader.readAsText(blob);
reader.onloadend = () => {
if (reader.result) {
setResult(JSON.stringify(reader.result));
}
};
};
// const pasteHelper = (blob: Blob, setResult: (result: string) => void): void => {
// const reader = new FileReader();
// reader.readAsText(blob);
// reader.onloadend = () => {
// if (reader.result) {
// setResult(JSON.stringify(reader.result));
// }
// };
// };

const Paste = (): React.ReactElement =>
ApiWithoutInput({
name: 'paste',
title: 'Paste',
onClick: async (setResult) => {
const result = await clipboard.read();
if (result.type.startsWith('text')) {
pasteHelper(result, setResult);
return 'clipboard.read()' + noHostSdkMsg;
} else if (result.type.startsWith('image')) {
image.src = URL.createObjectURL(result);
image.style.height = '150px';
image.style.width = '150px';
const root = document.getElementById('root');
if (root) {
root.appendChild(image);
}
return JSON.stringify(`Pasted from clipboard with image id: ${image.id}`);
} else {
return JSON.stringify('No contents read from clipboard.');
}
},
});
const ClipboardAPIs: React.FC = () => (
<ModuleWrapper title="Clipboard">
<CopyText />
<CopyImage />
<Paste />
<CheckCallCapability />
</ModuleWrapper>
);
// const Paste = (): React.ReactElement =>
// ApiWithoutInput({
// name: 'paste',
// title: 'Paste',
// onClick: async (setResult) => {
// const result = await clipboard.read();
// if (result.type.startsWith('text')) {
// pasteHelper(result, setResult);
// return 'clipboard.read()' + noHostSdkMsg;
// } else if (result.type.startsWith('image')) {
// image.src = URL.createObjectURL(result);
// image.style.height = '150px';
// image.style.width = '150px';
// const root = document.getElementById('root');
// if (root) {
// root.appendChild(image);
// }
// return JSON.stringify(`Pasted from clipboard with image id: ${image.id}`);
// } else {
// return JSON.stringify('No contents read from clipboard.');
// }
// },
// });
// const ClipboardAPIs: React.FC = () => (
// <ModuleWrapper title="Clipboard">
// <CopyText />
// <CopyImage />
// <Paste />
// <CheckCallCapability />
// </ModuleWrapper>
// );

export default ClipboardAPIs;
// export default ClipboardAPIs;
1 change: 1 addition & 0 deletions packages/teams-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"main": "./dist/MicrosoftTeams.min.js",
"typings": "./dist/MicrosoftTeams.d.ts",
"sideEffects": false,
"scripts": {
"build": "pnpm lint && webpack && pnpm docs:validate",
"clean": "rimraf ./dist",
Expand Down
157 changes: 74 additions & 83 deletions packages/teams-js/src/public/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,94 +13,85 @@ import { runtime } from './runtime';
const clipboardTelemetryVersionNumber: ApiVersionNumber = ApiVersionNumber.V_2;

/**
* Interact with the system clipboard
* Function to copy data to clipboard.
* @remarks
* Note: clipboard.write only supports Text, HTML, PNG, and JPEG data format.
* MIME type for Text -> `text/plain`, HTML -> `text/html`, PNG/JPEG -> `image/(png | jpeg)`
* Also, JPEG will be converted to PNG image when copying to clipboard.
*
* @beta
* @param blob - A Blob object representing the data to be copied to clipboard.
* @returns A string promise which resolves to success message from the clipboard or
* rejects with error stating the reason for failure.
*/
export namespace clipboard {
/**
* Function to copy data to clipboard.
* @remarks
* Note: clipboard.write only supports Text, HTML, PNG, and JPEG data format.
* MIME type for Text -> `text/plain`, HTML -> `text/html`, PNG/JPEG -> `image/(png | jpeg)`
* Also, JPEG will be converted to PNG image when copying to clipboard.
*
* @param blob - A Blob object representing the data to be copied to clipboard.
* @returns A string promise which resolves to success message from the clipboard or
* rejects with error stating the reason for failure.
*/
export async function write(blob: Blob): Promise<void> {
ensureInitialized(
runtime,
FrameContexts.content,
FrameContexts.meetingStage,
FrameContexts.task,
FrameContexts.settings,
FrameContexts.stage,
FrameContexts.sidePanel,
);
if (!isSupported()) {
throw errorNotSupportedOnPlatform;
}
if (!(blob.type && Object.values(ClipboardSupportedMimeType).includes(blob.type as ClipboardSupportedMimeType))) {
throw new Error(
`Blob type ${blob.type} is not supported. Supported blob types are ${Object.values(
ClipboardSupportedMimeType,
)}`,
);
}
const base64StringContent = await utils.getBase64StringFromBlob(blob);
const writeParams: ClipboardParams = {
mimeType: blob.type as ClipboardSupportedMimeType,
content: base64StringContent,
};
return sendAndHandleSdkError(
getApiVersionTag(clipboardTelemetryVersionNumber, ApiName.Clipboard_Write),
'clipboard.writeToClipboard',
writeParams,
);
export async function write(blob: Blob): Promise<void> {
ensureInitialized(
runtime,
FrameContexts.content,
FrameContexts.meetingStage,
FrameContexts.task,
FrameContexts.settings,
FrameContexts.stage,
FrameContexts.sidePanel,
);
if (!isSupported()) {
throw errorNotSupportedOnPlatform;
}

/**
* Function to read data from clipboard.
*
* @returns A promise blob which resolves to the data read from the clipboard or
* rejects stating the reason for failure.
* Note: Returned blob type will contain one of the MIME type `image/png`, `text/plain` or `text/html`.
*/
export async function read(): Promise<Blob> {
ensureInitialized(
runtime,
FrameContexts.content,
FrameContexts.meetingStage,
FrameContexts.task,
FrameContexts.settings,
FrameContexts.stage,
FrameContexts.sidePanel,
if (!(blob.type && Object.values(ClipboardSupportedMimeType).includes(blob.type as ClipboardSupportedMimeType))) {
throw new Error(
`Blob type ${blob.type} is not supported. Supported blob types are ${Object.values(ClipboardSupportedMimeType)}`,
);
const apiVersionTag = getApiVersionTag(clipboardTelemetryVersionNumber, ApiName.Clipboard_Read);
if (!isSupported()) {
throw errorNotSupportedOnPlatform;
}
if (isHostClientMobile() || GlobalVars.hostClientType === HostClientType.macos) {
const response = JSON.parse(
await sendAndHandleSdkError(apiVersionTag, 'clipboard.readFromClipboard'),
) as ClipboardParams;
return utils.base64ToBlob(response.mimeType, response.content);
} else {
return sendAndHandleSdkError(apiVersionTag, 'clipboard.readFromClipboard');
}
}
const base64StringContent = await utils.getBase64StringFromBlob(blob);
const writeParams: ClipboardParams = {
mimeType: blob.type as ClipboardSupportedMimeType,
content: base64StringContent,
};
return sendAndHandleSdkError(
getApiVersionTag(clipboardTelemetryVersionNumber, ApiName.Clipboard_Write),
'clipboard.writeToClipboard',
writeParams,
);
}

/**
* Checks if clipboard capability is supported by the host
* @returns boolean to represent whether the clipboard capability is supported
*
* @throws Error if {@linkcode app.initialize} has not successfully completed
*
* @beta
*/
export function isSupported(): boolean {
return ensureInitialized(runtime) && navigator && navigator.clipboard && runtime.supports.clipboard ? true : false;
/**
* Function to read data from clipboard.
*
* @returns A promise blob which resolves to the data read from the clipboard or
* rejects stating the reason for failure.
* Note: Returned blob type will contain one of the MIME type `image/png`, `text/plain` or `text/html`.
*/
export async function read(): Promise<Blob> {
ensureInitialized(
runtime,
FrameContexts.content,
FrameContexts.meetingStage,
FrameContexts.task,
FrameContexts.settings,
FrameContexts.stage,
FrameContexts.sidePanel,
);
const apiVersionTag = getApiVersionTag(clipboardTelemetryVersionNumber, ApiName.Clipboard_Read);
if (!isSupported()) {
throw errorNotSupportedOnPlatform;
}
if (isHostClientMobile() || GlobalVars.hostClientType === HostClientType.macos) {
const response = JSON.parse(
await sendAndHandleSdkError(apiVersionTag, 'clipboard.readFromClipboard'),
) as ClipboardParams;
return utils.base64ToBlob(response.mimeType, response.content);
} else {
return sendAndHandleSdkError(apiVersionTag, 'clipboard.readFromClipboard');
}
}

/**
* Checks if clipboard capability is supported by the host
* @returns boolean to represent whether the clipboard capability is supported
*
* @throws Error if {@linkcode app.initialize} has not successfully completed
*
* @beta
*/
export function isSupported(): boolean {
return ensureInitialized(runtime) && navigator && navigator.clipboard && runtime.supports.clipboard ? true : false;
}