@googleworkspace/drive-picker-element
Version:
A web component for Google Drive Picker
1 lines • 36.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/utils.ts","../src/drive-picker/drive-picker-docs-view-element.ts","../src/drive-picker/drive-picker-element.ts","../src/index.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst GAPI_URL = \"https://apis.google.com/js/api.js\";\nexport const GSI_URL = \"https://accounts.google.com/gsi/client\";\n\nexport async function loadApi(api = \"client:picker\"): Promise<typeof google> {\n\tif (!window.gapi) {\n\t\tawait injectScript(GAPI_URL);\n\t}\n\n\tawait new Promise<void>((r) => {\n\t\twindow.gapi.load(api, r);\n\t});\n\n\treturn window.google;\n}\n\nexport class ClientConfigError extends Error {\n\tconstructor(\n\t\tpublic readonly configError: google.accounts.oauth2.ClientConfigError,\n\t) {\n\t\tsuper(configError.message);\n\t}\n}\n\nexport async function requestAccessToken(\n\ttokenClientConfig: Omit<\n\t\tgoogle.accounts.oauth2.TokenClientConfig,\n\t\t\"callback\" | \"error_callback\"\n\t>,\n): Promise<google.accounts.oauth2.TokenResponse> {\n\tif (!window.google?.accounts?.oauth2) {\n\t\tawait injectScript(GSI_URL);\n\t}\n\treturn new Promise((resolve, reject) => {\n\t\tconst client = window.google.accounts.oauth2.initTokenClient({\n\t\t\t...tokenClientConfig,\n\t\t\tcallback: resolve,\n\t\t\terror_callback: reject,\n\t\t});\n\n\t\tclient.requestAccessToken();\n\t});\n}\n\n/**\n * Injects a script into the document head.\n *\n * This function always creates and appends a new script element, even if a script with the same src\n * already exists. This is done to avoid race conditions where an existing script might have already\n * loaded (or failed) before we could attach event listeners, causing the promise to hang indefinitely.\n *\n * To ensure compatibility with Content Security Policy (CSP) and other requirements, this function\n * copies all attributes (including `nonce`, `integrity`, `crossorigin`, etc.) from any existing\n * script tag with the same src to the new script tag.\n *\n * Note: The script at the provided `src` must be idempotent, as it may be executed multiple times\n * if it is already present in the document.\n */\nexport async function injectScript(src: string): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst newScript = document.createElement(\"script\");\n\t\tnewScript.src = src;\n\t\tnewScript.onload = () => resolve();\n\t\tnewScript.onerror = (err) => reject(err);\n\n\t\t// Check for an existing script to copy attributes from.\n\t\t// This is important for CSP compliance (nonce, integrity) and other attributes.\n\t\tconst existingScript = document.querySelector<HTMLScriptElement>(\n\t\t\t`script[src=\"${src}\"]`,\n\t\t);\n\t\tif (existingScript) {\n\t\t\tconsole.log(\n\t\t\t\t`drive-picker: appending a copy of an existing script ${src}`,\n\t\t\t);\n\t\t\t// Copy all attributes except those that would conflict or are handled manually\n\t\t\tArray.from(existingScript.attributes).forEach((attr) => {\n\t\t\t\tif ([\"id\", \"src\", \"onload\", \"onerror\"].includes(attr.name)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tnewScript.setAttribute(attr.name, attr.value);\n\t\t\t});\n\n\t\t\t// Nonce must be copied as a property because it's not always exposed in attributes.\n\t\t\t// The nonce attribute is hidden from getAttribute() and attributes for security reasons.\n\t\t\t// It is safe to reuse the same nonce for multiple scripts on the same page (same HTTP response).\n\t\t\tif (existingScript.nonce) {\n\t\t\t\tnewScript.nonce = existingScript.nonce;\n\t\t\t}\n\t\t}\n\n\t\tdocument.head.appendChild(newScript);\n\t});\n}\n\nexport function getNumberAttribute(\n\telement: Element,\n\tname: string,\n): number | null {\n\tconst value = element.getAttribute(name);\n\treturn value ? Number(value) : null;\n}\n\nexport enum BoolAttrWithDefault {\n\tFALSE = 0,\n\tTRUE = 1,\n\tDEFAULT = 2,\n}\n\nexport function getBoolAttr(element: Element, name: string): boolean {\n\treturn element.hasAttribute(name);\n}\n\nexport function getBoolAttrWithDefault(\n\telement: Element,\n\tname: string,\n): BoolAttrWithDefault {\n\tconst attributeValue = element.getAttribute(name)?.toUpperCase();\n\n\tif (!attributeValue) {\n\t\treturn BoolAttrWithDefault.DEFAULT;\n\t}\n\n\tconst value =\n\t\tBoolAttrWithDefault[attributeValue as keyof typeof BoolAttrWithDefault];\n\n\tif (value !== undefined) {\n\t\treturn value;\n\t}\n\n\tthrow new Error(\n\t\t`Invalid value, \"${attributeValue}\", for attribute ${name}. Must be one of ${Object.keys(BoolAttrWithDefault).filter(Number.isNaN).join(\", \")}`,\n\t);\n}\n\nexport function setBoolAttrWithDefault<T>(\n\tname: string,\n\telement: Element,\n\tsetter: (value: boolean) => T,\n\tinstance: T,\n): T {\n\tconst attr = getBoolAttrWithDefault(element, name);\n\n\tif (attr === BoolAttrWithDefault.DEFAULT) {\n\t\treturn instance;\n\t}\n\n\treturn setter.call(instance, attr === BoolAttrWithDefault.TRUE);\n}\n","/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { setBoolAttrWithDefault } from \"../utils\";\n\ntype ViewId = keyof typeof google.picker.ViewId;\n\n/**\n * The `drive-picker-docs-view` element is used to define a [`google.picker.DocsView`](https://developers.google.com/drive/picker/reference/picker.docsview).\n *\n * @element drive-picker-docs-view\n * @attr {\"default\"|\"true\"|\"false\"} enable-drives - Whether to allow the user to select files from shared drives. See [`DocsView.enableDrives`](https://developers.google.com/drive/picker/reference/picker.docsview.setenabledrives).\n * @attr {\"default\"|\"true\"|\"false\"} include-folders - Whether to include folders in the view. See [`DocsView.includeFolders`](https://developers.google.com/drive/picker/reference/picker.docsview.setincludefolders).\n * @attr {string} mime-types - A comma-separated list of MIME types to filter the view. See [`View.setMimeTypes`](https://developers.google.com/drive/picker/reference/picker.view.setmimetypes).\n * @attr {string} file-ids - A comma-separated list of file IDs to filter the view. See [`View.setFileIds`](https://developers.google.com/workspace/drive/picker/reference/picker.docsview.setfileids).\n * @attr {string} mode - The mode of the view. See [`DocsViewMode`](https://developers.google.com/drive/picker/reference/picker.docsviewmode).\n * @attr {\"default\"|\"true\"|\"false\"} owned-by-me - Whether to show files owned by the user. See [`DocsView.ownedByMe`](https://developers.google.com/drive/picker/reference/picker.docsview.setownedbyme).\n * @attr {string} parent - The ID of the folder to view. See [`DocsView.setParent`](https://developers.google.com/drive/picker/reference/picker.docsview.setparent).\n * @attr {string} query - The query string to filter the view. See [`View.setQuery`](https://developers.google.com/drive/picker/reference/picker.view.setquery).\n * @attr {\"default\"|\"true\"|\"false\"} select-folder-enabled - Whether to allow the user to select folders. See [`DocsView.selectFolderEnabled`](https://developers.google.com/drive/picker/reference/picker.docsview.setselectfolderenabled).\n * @attr {\"default\"|\"true\"|\"false\"} starred - Whether to show starred files. See [`DocsView.starred`](https://developers.google.com/drive/picker/reference/picker.docsview.setstarred).\n * @attr {string} view-id - 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).\n *\n * @example\n *\n * ```html\n * <drive-picker-docs-view ownedByMe=\"\"></drive-picker-docs-view>\n * ```\n *\n * @see https://developers.google.com/drive/picker/reference/picker.docsview\n *\n */\nexport class DrivePickerDocsViewElement extends HTMLElement {\n\tstatic get observedAttributes() {\n\t\treturn [\n\t\t\t\"enable-drives\",\n\t\t\t\"file-ids\",\n\t\t\t\"include-folders\",\n\t\t\t\"mime-types\",\n\t\t\t\"mode\",\n\t\t\t\"owned-by-me\",\n\t\t\t\"parent\",\n\t\t\t\"query\",\n\t\t\t\"select-folder-enabled\",\n\t\t\t\"starred\",\n\t\t\t\"view-id\",\n\t\t];\n\t}\n\n\t/**\n\t * Gets the Google Drive Picker view based on the current attribute values.\n\t * @returns {google.picker.DocsView} The Google Drive picker view.\n\t */\n\tpublic get view(): google.picker.DocsView {\n\t\tconst view = new window.google.picker.DocsView(this.viewId);\n\n\t\tsetBoolAttrWithDefault(\"enable-drives\", this, view.setEnableDrives, view);\n\t\tsetBoolAttrWithDefault(\n\t\t\t\"include-folders\",\n\t\t\tthis,\n\t\t\tview.setIncludeFolders,\n\t\t\tview,\n\t\t);\n\t\tsetBoolAttrWithDefault(\"owned-by-me\", this, view.setOwnedByMe, view);\n\t\tsetBoolAttrWithDefault(\n\t\t\t\"select-folder-enabled\",\n\t\t\tthis,\n\t\t\tview.setSelectFolderEnabled,\n\t\t\tview,\n\t\t);\n\t\tsetBoolAttrWithDefault(\"starred\", this, view.setStarred, view);\n\n\t\tconst mimetypes = this.getAttribute(\"mime-types\");\n\t\tif (mimetypes !== null) view.setMimeTypes(mimetypes);\n\n\t\tconst fileIds = this.getAttribute(\"file-ids\");\n\t\tif (fileIds !== null) view.setFileIds(fileIds);\n\n\t\tconst mode = this.getAttribute(\"mode\");\n\t\tif (mode)\n\t\t\tview.setMode(\n\t\t\t\tgoogle.picker.DocsViewMode[\n\t\t\t\t\tmode as keyof typeof google.picker.DocsViewMode\n\t\t\t\t],\n\t\t\t);\n\n\t\tconst parent = this.getAttribute(\"parent\");\n\t\tif (parent !== null) view.setParent(parent);\n\n\t\tconst query = this.getAttribute(\"query\");\n\t\tif (query !== null) view.setQuery(query);\n\n\t\treturn view;\n\t}\n\n\tprivate get viewId(): google.picker.ViewId | undefined {\n\t\tconst viewId = this.getAttribute(\"view-id\");\n\t\treturn viewId ? window.google.picker.ViewId[viewId as ViewId] : undefined;\n\t}\n}\n","/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\tgetBoolAttr,\n\tgetNumberAttribute,\n\tloadApi,\n\trequestAccessToken,\n\tsetBoolAttrWithDefault,\n} from \"../utils\";\n\ntype View = google.picker.DocsView;\n\ninterface DrivePickerDocsViewElement extends HTMLElement {\n\tview: google.picker.DocsView;\n}\n\nexport type OAuthErrorEvent = CustomEvent<\n\t| google.accounts.oauth2.ClientConfigError\n\t| google.accounts.oauth2.TokenResponse\n>;\nexport type OAuthResponseEvent =\n\tCustomEvent<google.accounts.oauth2.TokenResponse>;\nexport type PickerCanceledEvent = CustomEvent<google.picker.ResponseObject>;\nexport type PickerPickedEvent = CustomEvent<google.picker.ResponseObject>;\nexport type PickerErrorEvent = CustomEvent<unknown>;\n\ndeclare global {\n\tinterface GlobalEventHandlersEventMap {\n\t\t/** @deprecated - Use \"picker-oauth-error\" */\n\t\t\"picker:authenticated\": CustomEvent<{ token: string }>;\n\t\t/** @deprecated - Use \"picker-oauth-error\" */\n\t\t\"picker:oauth:error\": OAuthErrorEvent;\n\t\t\"picker-oauth-error\": OAuthErrorEvent;\n\t\t/** @deprecated - Use \"picker-oauth-response\" */\n\t\t\"picker:oauth:response\": OAuthResponseEvent;\n\t\t\"picker-oauth-response\": OAuthResponseEvent;\n\t\t/** @deprecated - Use \"picker-canceled\" */\n\t\t\"picker:canceled\": PickerCanceledEvent;\n\t\t\"picker-canceled\": PickerCanceledEvent;\n\t\t/** @deprecated - Use \"picker-picked\" */\n\t\t\"picker:picked\": PickerPickedEvent;\n\t\t\"picker-picked\": PickerPickedEvent;\n\t\t/** @deprecated - Use \"picker-error\" */\n\t\t\"picker:error\": PickerErrorEvent;\n\t\t\"picker-error\": PickerErrorEvent;\n\t}\n}\n\n/**\n * The `drive-picker` web component provides a convenient way to declaratively\n * build\n * [`google.picker.Picker`](https://developers.google.com/drive/picker/reference/picker)\n * by using the component attributes mapped to the corresponding methods of\n * [`google.picker.PickerBuilder`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder).\n *\n * @element drive-picker\n *\n * @fires {PickerCanceledEvent} picker-canceled - Triggered when the user cancels the picker dialog. See [`ResponseObject`](https://developers.google.com/drive/picker/reference/picker.responseobject).\n * @fires {PickerPickedEvent} picker-picked - Triggered when the user picks one or more items. See [`ResponseObject`](https://developers.google.com/drive/picker/reference/picker.responseobject).\n * @fires {PickerErrorEvent} picker-error - Triggered when an error occurs. See [`ResponseObject`](https://developers.google.com/drive/picker/reference/picker.responseobject).\n * @fires {OAuthErrorEvent} picker-oauth-error - Triggered when an error occurs in the OAuth flow. See the [error guide](https://developers.google.com/identity/oauth2/web/guides/error). Note that the `TokenResponse` object can have error fields.\n * @fires {OAuthResponseEvent} picker-oauth-response - Triggered when an OAuth flow completes. See the [token model guide](https://developers.google.com/identity/oauth2/web/guides/use-token-model).\n *\n * @slot - The default slot contains View elements to display in the picker.\n * Each View element should implement a property `view` of type\n * `google.picker.View`.\n * @attr {string} app-id - The Google Drive app ID. See [`PickerBuilder.setAppId`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setappid).\n * @attr {string} client-id - The OAuth 2.0 client ID. See [Using OAuth 2.0 to Access Google APIs](https://developers.google.com/identity/protocols/oauth2).\n * @attr {string} developer-key - The API key for accessing Google Picker API. See [`PickerBuilder.setDeveloperKey`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setdeveloperkey).\n * @attr {number} [debounce-delay=0] - The debounce delay in milliseconds before building the picker after an attribute change.\n * @attr {\"default\"|\"true\"|\"false\"} hide-title-bar - Hides the title bar of the\n * picker if set to true. See [`PickerBuilder.hideTitleBar`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.hidetitlebar).\n * @attr {string} locale - The locale to use for the picker. See [`PickerBuilder.setLocale`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setlocale).\n * @attr {number} max-items - The maximum number of items that can be selected. See [`PickerBuilder.setMaxItems`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setmaxitems).\n * @attr {boolean} mine-only - If set to true, only shows files owned by the\n * user. See [`PickerBuilder.enableFeature`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.enablefeature).\n * @attr {boolean} multiselect - Enables multiple file selection if set to true. See [`PickerBuilder.enableFeature`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.enablefeature).\n * @attr {boolean} nav-hidden - Hides the navigation pane if set to true. See [`PickerBuilder.enableFeature`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.enablefeature).\n * @attr {string} oauth-token - The OAuth 2.0 token for authentication. See [`PickerBuilder.setOAuthToken`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setoauthtoken).\n * @attr {string} origin - The origin parameter for the picker. See [`PickerBuilder.setOrigin`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setorigin).\n * @attr {string} relay-url - The relay URL for the picker. See [`PickerBuilder.setRelayUrl`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.setrelayurl).\n * @attr {string} scope - 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).\n * @attr {string} title - The title of the picker. See [`PickerBuilder.setTitle`](https://developers.google.com/drive/picker/reference/picker.pickerbuilder.settitle).\n * @attr {string} hd - The hosted domain to restrict sign-in to. (Optional) See the `hd` field in the OpenID Connect docs.\n * @attr {boolean} include-granted-scopes - Enables applications to use incremental authorization. See [`TokenClientConfig.include_granted_scopes`](https://developers.google.com/identity/oauth2/web/reference/js-reference#TokenClientConfig).\n * @attr {string} login-hint - 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.\n * @attr {\"\"|\"none\"|\"consent\"|\"select_account\"} prompt - 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)\n *\n * @example\n *\n *```html\n *<drive-picker\n * app-id=\"246724281745\"\n * client-id=\"246724281745-v9ouai8ood5o69r3ug29aaqeqflomijd.apps.googleusercontent.com\"\n *>\n * <drive-picker-docs-view></drive-picker-docs-view>\n *</drive-picker>\n *```\n *\n */\nexport class DrivePickerElement extends HTMLElement {\n\tstatic get observedAttributes() {\n\t\treturn [\n\t\t\t\"app-id\",\n\t\t\t\"client-id\",\n\t\t\t\"debounce-delay\",\n\t\t\t\"developer-key\",\n\t\t\t\"hide-title-bar\",\n\t\t\t\"locale\",\n\t\t\t\"max-items\",\n\t\t\t\"mine-only\",\n\t\t\t\"multiselect\",\n\t\t\t\"nav-hidden\",\n\t\t\t\"oauth-token\",\n\t\t\t\"origin\",\n\t\t\t\"relay-url\",\n\t\t\t\"scope\",\n\t\t\t\"title\",\n\t\t];\n\t}\n\tprivate picker: google.picker.Picker | undefined;\n\tprivate observer: MutationObserver | undefined;\n\tprivate google: typeof google | undefined;\n\tprivate loading: Promise<void> | undefined;\n\tprivate debounceTimer: number | undefined;\n\n\t/**\n\t * The visibility of the picker.\n\t */\n\tpublic get visible(): boolean {\n\t\treturn Boolean(this.picker?.isVisible());\n\t}\n\n\t/**\n\t * Controls the visibility of the picker after the picker dialog has been\n\t * closed. If any of the attributes change, the picker will be rebuilt and\n\t * the visibility will be reset.\n\t */\n\tset visible(value: boolean) {\n\t\tthis.picker?.setVisible(value);\n\t}\n\n\tpublic get tokenClientConfig(): Omit<\n\t\tgoogle.accounts.oauth2.TokenClientConfig,\n\t\t\"callback\" | \"error_callback\"\n\t> {\n\t\tconst clientId = this.getAttribute(\"client-id\");\n\t\tconst scope =\n\t\t\tthis.getAttribute(\"scope\") ??\n\t\t\t\"https://www.googleapis.com/auth/drive.file\";\n\n\t\tif (!clientId || !scope) {\n\t\t\tthrow new Error(\"client-id and scope are required attributes\");\n\t\t}\n\n\t\treturn {\n\t\t\tclient_id: clientId,\n\t\t\thd: this.getAttribute(\"hd\") ?? undefined,\n\t\t\tinclude_granted_scopes: Boolean(\n\t\t\t\tthis.getAttribute(\"include-granted-scope\"),\n\t\t\t),\n\t\t\tlogin_hint: this.getAttribute(\"login-hint\") ?? undefined,\n\t\t\tprompt: (this.getAttribute(\"prompt\") ??\n\t\t\t\t\"\") as google.accounts.oauth2.TokenClientConfig[\"prompt\"],\n\t\t\tscope,\n\t\t};\n\t}\n\n\tattributeChangedCallback() {\n\t\tif (!this.isConnected) return;\n\n\t\tthis.scheduleBuild();\n\t}\n\n\tprivate scheduleBuild() {\n\t\t// Clear any previously scheduled build to ensure we don't build multiple times\n\t\tclearTimeout(this.debounceTimer);\n\n\t\t// Schedule a new build to run after a short delay.\n\t\t// This coalesces multiple rapid changes into a single build call.\n\t\tthis.debounceTimer = window.setTimeout(() => {\n\t\t\tthis.build();\n\t\t}, getNumberAttribute(this, \"debounce-delay\") ?? 0);\n\t}\n\n\tprivate async build() {\n\t\tthis.picker?.dispose();\n\n\t\t// this await is necessary as an attribute may have changed\n\t\t// prior to the API initially being loaded\n\t\tawait this.loading;\n\n\t\tif (!this.google) return;\n\n\t\tlet builder = new this.google.picker.PickerBuilder().setCallback(\n\t\t\t(data: google.picker.ResponseObject) => {\n\t\t\t\tthis.callbackToDispatchEvent(data);\n\t\t\t},\n\t\t);\n\n\t\tconst appId = this.getAttribute(\"app-id\");\n\t\tif (appId) {\n\t\t\tbuilder = builder.setAppId(appId);\n\t\t} else {\n\t\t\tconsole.warn(\n\t\t\t\t\"drive-picker: app-id attribute is missing. This may cause issues with backend API integration.\",\n\t\t\t);\n\t\t}\n\n\t\tconst developerKey = this.getAttribute(\"developer-key\");\n\t\tif (developerKey !== null) builder = builder.setDeveloperKey(developerKey);\n\n\t\tconst locale = this.getAttribute(\"locale\");\n\t\tif (locale !== null)\n\t\t\tbuilder = builder.setLocale(locale as google.picker.Locales);\n\n\t\tconst maxItems = getNumberAttribute(this, \"max-items\");\n\t\tif (maxItems !== null) builder = builder.setMaxItems(maxItems);\n\n\t\tconst origin = this.getAttribute(\"origin\");\n\t\tif (origin !== null) builder = builder.setOrigin(origin);\n\n\t\tconst relayUrl = this.getAttribute(\"relay-url\");\n\t\tif (relayUrl !== null) builder = builder.setRelayUrl(relayUrl);\n\n\t\tconst title = this.getAttribute(\"title\");\n\t\tif (title !== null) builder = builder.setTitle(title);\n\n\t\tsetBoolAttrWithDefault(\n\t\t\t\"hide-title-bar\",\n\t\t\tthis,\n\t\t\tbuilder.hideTitleBar,\n\t\t\tbuilder,\n\t\t);\n\n\t\t// OAuth token is required either as an attribute or from the OAuth flow using the client ID and scope\n\t\tconst oauthToken =\n\t\t\tthis.getAttribute(\"oauth-token\") ?? (await this.requestAccessToken());\n\n\t\tif (!oauthToken) return;\n\n\t\tbuilder = builder.setOAuthToken(oauthToken);\n\n\t\tif (getBoolAttr(this, \"multiselect\")) {\n\t\t\tbuilder = builder.enableFeature(\n\t\t\t\tthis.google.picker.Feature.MULTISELECT_ENABLED,\n\t\t\t);\n\t\t}\n\n\t\tif (getBoolAttr(this, \"mine-only\")) {\n\t\t\tbuilder = builder.enableFeature(this.google.picker.Feature.MINE_ONLY);\n\t\t}\n\n\t\tif (getBoolAttr(this, \"nav-hidden\")) {\n\t\t\tbuilder = builder.enableFeature(this.google.picker.Feature.NAV_HIDDEN);\n\t\t}\n\n\t\tfor (const view of this.views) {\n\t\t\tbuilder = builder.addView(view);\n\t\t}\n\n\t\tthis.picker = builder.build();\n\n\t\tthis.picker.setVisible(true);\n\t}\n\n\t/**\n\t * The `google.Picker.View` objects to display in the picker as defined by the slot elements.\n\t */\n\tprivate get views(): (View | google.picker.ViewId)[] {\n\t\tconst views = nestedViews(this);\n\t\treturn views.length ? views : [\"all\" as google.picker.ViewId];\n\t}\n\n\tasync connectedCallback(): Promise<void> {\n\t\tthis.loading = loadApi().then((google) => {\n\t\t\tthis.google = google;\n\t\t});\n\n\t\t// Watch for changes in the picker element slot and their attributes\n\t\tthis.observer = new MutationObserver((mutations) => {\n\t\t\tconst filteredMutations = mutations.filter(\n\t\t\t\t(mutation) =>\n\t\t\t\t\tmutation.type === \"childList\" ||\n\t\t\t\t\t(mutation.type === \"attributes\" && mutation.target !== this),\n\t\t\t);\n\n\t\t\tif (filteredMutations.length) {\n\t\t\t\tthis.scheduleBuild();\n\t\t\t}\n\t\t});\n\n\t\tthis.observer?.observe(this, {\n\t\t\tchildList: true,\n\t\t\tsubtree: true,\n\t\t\tattributes: true,\n\t\t});\n\n\t\tthis.scheduleBuild();\n\t}\n\n\tprivate callbackToDispatchEvent(detail: google.picker.ResponseObject) {\n\t\t// TODO - remove deprecated events\n\t\tlet eventTypes: (keyof GlobalEventHandlersEventMap)[];\n\n\t\tswitch (detail.action) {\n\t\t\tcase google.picker.Action.CANCEL:\n\t\t\t\teventTypes = [\"picker:canceled\", \"picker-canceled\"];\n\t\t\t\tbreak;\n\t\t\tcase google.picker.Action.PICKED:\n\t\t\t\teventTypes = [\"picker:picked\", \"picker-picked\"];\n\t\t\t\tbreak;\n\t\t\tcase google.picker.Action.ERROR:\n\t\t\t\teventTypes = [\"picker:error\", \"picker-error\"];\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn;\n\t\t}\n\n\t\tfor (const eventType of eventTypes) {\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent(eventType, {\n\t\t\t\t\tdetail,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async requestAccessToken(): Promise<string | undefined> {\n\t\treturn requestAccessToken(this.tokenClientConfig)\n\t\t\t.then((response) => {\n\t\t\t\tconst { access_token: token } = response;\n\t\t\t\tif (!token) {\n\t\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\t\tnew CustomEvent(\"picker:oauth:error\", {\n\t\t\t\t\t\t\tdetail: response,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\t\tnew CustomEvent(\"picker-oauth-error\", {\n\t\t\t\t\t\t\tdetail: response,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\t// TODO - remove deprecated event\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"picker:authenticated\", { detail: { token } }),\n\t\t\t\t);\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"picker-oauth-response\", { detail: response }),\n\t\t\t\t);\n\t\t\t\t// TODO - remove deprecated event\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"picker:oauth:response\", { detail: response }),\n\t\t\t\t);\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"picker-oauth-response\", { detail: response }),\n\t\t\t\t);\n\t\t\t\treturn token;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\t// TODO - remove deprecated event\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"picker:oauth:error\", {\n\t\t\t\t\t\tdetail: error,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent(\"picker-oauth-error\", {\n\t\t\t\t\t\tdetail: error,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn undefined;\n\t\t\t});\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tthis.picker?.dispose();\n\t}\n}\n\nfunction isView(obj: HTMLElement): obj is DrivePickerDocsViewElement {\n\treturn \"view\" in obj && obj.view instanceof window.google.picker.View;\n}\n\nfunction filterElementsToViewOrViewGroup(\n\telements: Array<HTMLElement>,\n): Array<View> {\n\treturn elements\n\t\t.filter((element) => isView(element))\n\t\t.map((element) => element.view);\n}\n\nfunction nestedViews(target: HTMLElement, selector = \"*\"): Array<View> {\n\treturn filterElementsToViewOrViewGroup(\n\t\tArray.from(target.querySelectorAll<HTMLElement>(selector)),\n\t);\n}\n","/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\tDrivePickerDocsViewElement,\n\ttype DrivePickerDocsViewElementProps,\n\tDrivePickerElement,\n\ttype DrivePickerElementProps,\n\ttype OAuthErrorEvent,\n\ttype OAuthResponseEvent,\n\ttype PickerCanceledEvent,\n\ttype PickerErrorEvent,\n\ttype PickerPickedEvent,\n} from \"./drive-picker\";\n\ncustomElements.define(\"drive-picker\", DrivePickerElement);\ncustomElements.define(\"drive-picker-docs-view\", DrivePickerDocsViewElement);\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t\"drive-picker\": DrivePickerElement;\n\t}\n\tinterface HTMLElementTagNameMap {\n\t\t\"drive-picker-docs-view\": DrivePickerDocsViewElement;\n\t}\n}\n\nexport type {\n\tDrivePickerElement,\n\tDrivePickerDocsViewElement,\n\tDrivePickerElementProps,\n\tDrivePickerDocsViewElementProps,\n\tOAuthErrorEvent,\n\tOAuthResponseEvent,\n\tPickerCanceledEvent,\n\tPickerErrorEvent,\n\tPickerPickedEvent,\n};\n"],"mappings":"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","names":["GAPI_URL","GSI_URL","loadApi","api","injectScript","r","requestAccessToken","tokenClientConfig","injectScript","GSI_URL","resolve","reject","src","newScript","err","existingScript","attr","getNumberAttribute","element","name","value","BoolAttrWithDefault","getBoolAttr","getBoolAttrWithDefault","attributeValue","setBoolAttrWithDefault","setter","instance","DrivePickerDocsViewElement","view","setBoolAttrWithDefault","mimetypes","fileIds","mode","parent","query","viewId","DrivePickerElement","value","clientId","scope","getNumberAttribute","builder","data","appId","developerKey","locale","maxItems","origin","relayUrl","title","setBoolAttrWithDefault","oauthToken","getBoolAttr","view","views","nestedViews","loadApi","google","mutations","mutation","detail","eventTypes","eventType","requestAccessToken","response","token","error","isView","obj","filterElementsToViewOrViewGroup","elements","element","target","selector","DrivePickerElement","DrivePickerDocsViewElement"]}