Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ See the framework specific demos:
- [Listening to Events](#listening-to-events)
- [Event Details](#event-details)
- [Controlling Visibility](#controlling-visibility)
- [React and JSX](#react-and-jsx)
- [Support](#support)
- [Reference](#reference)
- [`<drive-picker/>`](#drive-picker)
Expand Down Expand Up @@ -162,6 +163,37 @@ To make the picker visible, set the `visible` property of the `drive-picker` ele

After the picker dialog has been closed, the `visible` property will be reset to `false`.

### React and JSX

To use the component in a React application, you can extend the global `JSX` namespace as follows:

```ts
import type {
DrivePickerElement,
DrivePickerDocsViewElement,
DrivePickerElementProps,
DrivePickerDocsViewElementProps,
} from "@googleworkspace/drive-picker-element";

declare global {
namespace JSX {
interface IntrinsicElements {
"drive-picker": React.DetailedHTMLProps<
React.HTMLAttributes<DrivePickerElement> & DrivePickerElementProps,
DrivePickerElement
>;
"drive-picker-docs-view": React.DetailedHTMLProps<
React.HTMLAttributes<DrivePickerDocsViewElement> &
DrivePickerDocsViewElementProps,
DrivePickerDocsViewElement
>;
}
}
}
```

The above snippet can be added to a declaration file (e.g. `app.d.ts`) in your React project.

## Support

To report issues or feature requests for the underlying Drive Picker, please use the [Google Picker issue tracker](https://developers.google.com/drive/picker/support#developer_product_feedback). For all other issues, please use the [GitHub issue tracker](https://github.com/googleworkspace/drive-picker-element/issues).
Expand Down
34 changes: 33 additions & 1 deletion custom-elements.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@
"name": "DrivePickerDocsViewElement",
"module": "src/index.ts"
}
},
{
"kind": "js",
"name": "DrivePickerElementProps",
"declaration": {
"name": "DrivePickerElementProps",
"module": "src/index.ts"
}
},
{
"kind": "js",
"name": "DrivePickerDocsViewElementProps",
"declaration": {
"name": "DrivePickerDocsViewElementProps",
"module": "src/index.ts"
}
}
]
},
Expand Down Expand Up @@ -484,12 +500,28 @@
"name": "DrivePickerDocsViewElement",
"module": "\"./drive-picker-docs-view-element\""
}
},
{
"kind": "js",
"name": "DrivePickerDocsViewElementProps",
"declaration": {
"name": "DrivePickerDocsViewElementProps",
"module": "\"./props\""
}
},
{
"kind": "js",
"name": "DrivePickerElementProps",
"declaration": {
"name": "DrivePickerElementProps",
"module": "\"./props\""
}
}
]
},
{
"kind": "javascript-module",
"path": "src/drive-picker/types.ts",
"path": "src/drive-picker/props.ts",
"declarations": [],
"exports": []
}
Expand Down
17 changes: 16 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@
"build:components",
"build:manifest",
"build:readme",
"build:storybook"
"build:storybook",
"build:props"
]
},
"build:components": {
Expand All @@ -107,6 +108,20 @@
"dist/**/*.(js|ts|map)"
]
},
"build:props": {
"clean": false,
"command": "tsx ./scripts/props.ts",
"files": [
"custom-elements.json",
"scripts/props.ts"
],
"output": [
"src/drive-picker/props.ts"
],
"dependencies": [
"build:manifest"
]
},
"build:manifest": {
"command": "cem analyze --config cem.config.js && biome check --fix custom-elements.json",
"files": [
Expand Down
124 changes: 124 additions & 0 deletions scripts/props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import fs from "node:fs";
import prettier from "prettier";
import ts, { factory } from "typescript";

import type {
CustomElementDeclaration,
Declaration,
Package,
} from "custom-elements-manifest/schema";

const manifest = JSON.parse(
fs.readFileSync("custom-elements.json", "utf-8"),
) as Package;

function isCustomElementDeclaration(
declaration?: Declaration,
): declaration is CustomElementDeclaration {
return (declaration as CustomElementDeclaration)?.customElement === true;
}

const customElements = manifest.modules
.flatMap((module) => module.declarations)
.filter(isCustomElementDeclaration)
.sort((a, b) => a.tagName?.localeCompare(b.tagName ?? "") ?? 0);

const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
const resultFile = ts.createSourceFile(
"props.ts",
"",
ts.ScriptTarget.Latest,
false,
ts.ScriptKind.TS,
);

const statements: ts.Statement[] = [];

for (const element of customElements) {
const properties: ts.PropertySignature[] = [];

for (const attribute of element.attributes ?? []) {
// Create the property signature
const prop = factory.createPropertySignature(
undefined, // No modifiers
attribute.name.includes("-")
? factory.createStringLiteral(`${attribute.name}`)
: factory.createIdentifier(attribute.name),
factory.createToken(ts.SyntaxKind.QuestionToken), // Make props optional
factory.createTypeReferenceNode(
attribute.type?.text ?? "unknown",
undefined,
),
);

if (attribute.description) {
const jsDocText = `* ${attribute.description.replace(/\n/g, "\n * ")}`;
ts.addSyntheticLeadingComment(
prop,
ts.SyntaxKind.MultiLineCommentTrivia,
jsDocText,
true,
);
}

properties.push(prop);
}

const propsInterface = factory.createInterfaceDeclaration(
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier(`${element.name}Props`),
undefined,
undefined,
properties,
);

statements.push(propsInterface);
}

const outputFile = "src/drive-picker/props.ts";
const resultText = await prettier.format(
printer.printList(
ts.ListFormat.MultiLine,
factory.createNodeArray(statements),
resultFile,
),
{
parser: "typescript",
useTabs: true,
},
);

const licenseHeader = `/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/`;

fs.writeFileSync(outputFile, `${licenseHeader}\n\n${resultText}`, "utf8");
console.log(`Generated Drive Picker prop type definitions at ${outputFile}`);
5 changes: 5 additions & 0 deletions src/drive-picker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@
export { DrivePickerElement } from "./drive-picker-element";

export { DrivePickerDocsViewElement } from "./drive-picker-docs-view-element";

export type {
DrivePickerDocsViewElementProps,
DrivePickerElementProps,
} from "./props";
76 changes: 76 additions & 0 deletions src/drive-picker/props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export interface DrivePickerElementProps {
/** The Google Drive app ID. See [`PickerBuilder.setAppId`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setappid).*/
"app-id"?: string;
/** The OAuth 2.0 client ID. See [Using OAuth 2.0 to Access Google APIs](https://developers.google.com/identity/protocols/oauth2).*/
"client-id"?: string;
/** The API key for accessing Google Picker API. See [`PickerBuilder.setDeveloperKey`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setdeveloperkey).*/
"developer-key"?: string;
/** Hides the title bar of the picker if set to true. See [`PickerBuilder.hideTitleBar`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.hidetitlebar).*/
"hide-title-bar"?: "default" | "true" | "false";
/** The locale to use for the picker. See [`PickerBuilder.setLocale`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setlocale).*/
locale?: string;
/** The maximum number of items that can be selected. See [`PickerBuilder.setMaxItems`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setmaxitems).*/
"max-items"?: number;
/** If set to true, only shows files owned by the user. See [`PickerBuilder.enableFeature`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.enablefeature).*/
"mine-only"?: boolean;
/** Enables multiple file selection if set to true. See [`PickerBuilder.enableFeature`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.enablefeature).*/
multiselect?: boolean;
/** Hides the navigation pane if set to true. See [`PickerBuilder.enableFeature`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.enablefeature).*/
"nav-hidden"?: boolean;
/** The OAuth 2.0 token for authentication. See [`PickerBuilder.setOAuthToken`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setoauthtoken).*/
"oauth-token"?: string;
/** The origin parameter for the picker. See [`PickerBuilder.setOrigin`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setorigin).*/
origin?: string;
/** The relay URL for the picker. See [`PickerBuilder.setRelayUrl`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setrelayurl).*/
"relay-url"?: string;
/** The OAuth 2.0 scope for the picker. The default is `https://www.googleapis.com/auth/drive.file`. See [Drive API scopes](https://developers.google.com/drive/api/guides/api-specific-auth#drive-scopes).*/
scope?: string;
/** The title of the picker. See [`PickerBuilder.setTitle`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.settitle).*/
title?: string;
/** The hosted domain to restrict sign-in to. (Optional) See the `hd` field in the OpenID Connect docs.*/
hd?: string;
/** Enables applications to use incremental authorization. See [`TokenClientConfig.include_granted_scopes`](https://developers.google.com/identity/oauth2/web/reference/js-reference#TokenClientConfig).*/
"include-granted-scopes"?: boolean;
/** An email address or an ID token 'sub' value. Google will use the value as a hint of which user to sign in. See the `login_hint` field in the OpenID Connect docs.*/
"login-hint"?: string;
/** A space-delimited, case-sensitive list of prompts to present the user. See [`TokenClientConfig.prompt`](https://developers.google.com/identity/oauth2/web/reference/js-reference#TokenClientConfig)*/
prompt?: "" | "none" | "consent" | "select_account";
}
export interface DrivePickerDocsViewElementProps {
/** Whether to allow the user to select files from shared drives. See [`DocsView.enableDrives`](https://developers.google.com/drive/picker/reference/picker.docsview.setenabledrives).*/
"enable-drives"?: "default" | "true" | "false";
/** Whether to include folders in the view. See [`DocsView.includeFolders`](https://developers.google.com/drive/picker/reference/picker.docsview.setincludefolders).*/
"include-folders"?: "default" | "true" | "false";
/** A comma-separated list of MIME types to filter the view. See [`View.setMimeTypes`](https://developers.google.com/drive/picker/reference/picker.view.setmimetypes).*/
"mime-types"?: string;
/** The mode of the view. See [`DocsViewMode`](https://developers.google.com/drive/picker/reference/picker.docsviewmode).*/
mode?: string;
/** Whether to show files owned by the user. See [`DocsView.ownedByMe`](https://developers.google.com/drive/picker/reference/picker.docsview.setownedbyme).*/
"owned-by-me"?: "default" | "true" | "false";
/** The ID of the folder to view. See [`DocsView.setParent`](https://developers.google.com/drive/picker/reference/picker.docsview.setparent).*/
parent?: string;
/** The query string to filter the view. See [`View.setQuery`](https://developers.google.com/drive/picker/reference/picker.view.setquery).*/
query?: string;
/** Whether to allow the user to select folders. See [`DocsView.selectFolderEnabled`](https://developers.google.com/drive/picker/reference/picker.docsview.setselectfolderenabled).*/
"select-folder-enabled"?: "default" | "true" | "false";
/** Whether to show starred files. See [`DocsView.starred`](https://developers.google.com/drive/picker/reference/picker.docsview.setstarred).*/
starred?: "default" | "true" | "false";
/** The `keyof typeof google.picker.ViewId`. For example, `"DOCS"`, which is equivalent to `google.picker.ViewId.DOCS`. See [`ViewId`](https://developers.google.com/drive/picker/reference/picker.viewid).*/
"view-id"?: string;
}
15 changes: 0 additions & 15 deletions src/drive-picker/types.ts

This file was deleted.

14 changes: 12 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
* limitations under the License.
*/

import { DrivePickerDocsViewElement, DrivePickerElement } from "./drive-picker";
import {
DrivePickerDocsViewElement,
type DrivePickerDocsViewElementProps,
DrivePickerElement,
type DrivePickerElementProps,
} from "./drive-picker";

customElements.define("drive-picker", DrivePickerElement);
customElements.define("drive-picker-docs-view", DrivePickerDocsViewElement);
Expand All @@ -28,4 +33,9 @@ declare global {
}
}

export type { DrivePickerElement, DrivePickerDocsViewElement };
export type {
DrivePickerElement,
DrivePickerDocsViewElement,
DrivePickerElementProps,
DrivePickerDocsViewElementProps,
};