diff --git a/.babelrc b/.babelrc index 028dc10..657fe6e 100644 --- a/.babelrc +++ b/.babelrc @@ -2,9 +2,11 @@ "sourceMaps": true, "presets": [ "@babel/preset-env", + "@babel/preset-react", "@babel/preset-typescript" ], "plugins": [ - "@babel/plugin-proposal-class-properties" + "@babel/plugin-proposal-class-properties", + "@babel/plugin-transform-runtime" ] } diff --git a/README.md b/README.md index f7f5020..cfc32bb 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,117 @@ # matrix-react-sdk-module-api -Proof of concept API surface for writing Modules for the react-sdk -## TODO +API surface for interacting with the [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk) in a safe +and predictable way. -* [ ] Write a better intro/readme -* [ ] Proof of concept -* [ ] If approved, make it a real npm package -* [ ] If approved, fix access controls -* [ ] If approved, maintain this +Modules are simply additional functionality added at compile time for the application and can do things like register +custom translations, translation overrides, open dialogs, and add/modify UI. + +**Note**: This project is still considered alpha/beta quality due to the API surface not being extensive. Please reach +out in [#element-dev:matrix.org](https://matrix.to/#/#element-dev:matrix.org) on Matrix for guidance on how to add to +this API surface. + +In general, new code should target a generalized interface. An example would be the `openDialog()` function: while the +first module to use it didn't need custom `props`, it is expected that a dialog would at some point, so we expose it. +On the other hand, we deliberately do not expose the complexity of the react-sdk's dialog stack to this layer until +we need it. We might choose to open sticky dialogs with a new `openStickyDialog()` function instead of appending more +arguments to the existing function. + +## Using the API + +Modules are simply standalone npm packages which get installed/included in the app at compile time. To start, we +recommend using a simple module as a template, such as [element-web-ilag-module](https://github.com/vector-im/element-web-ilag-module). + +The package's `main` entrypoint MUST point to an instance of `RuntimeModule`. That class must be a `default` export +for the module loader to reference correctly. + +The `RuntimeModule` instance MUST have a constructor which accepts a single `ModuleApi` parameter. This is supplied +to the `super()` constructor. + +Otherwise, simply `npm install --save @matrix-org/react-sdk-module-api` and start coding! + +### Custom translations / string overrides + +Custom translation strings (used within your module) or string overrides can be specified using the `registerTranslations` +function on a `ModuleApi` instance. For example: + +```typescript +this.moduleApi.registerTranslations({ + // If you use the translation utilities within your module, register your strings + "My custom string": { + "en": "My custom string", + "fr": "Ma chaîne personnalisée", + }, + + // If you want to override a string already in the app, such as the power level role + // names, use the base string here and redefine the values for each applicable language. + "A string that might already exist in the app": { + "en": "Replacement value for that string", + "fr": "Valeur de remplacement pour cette chaîne", + }, +}); +``` + +If you are within a class provided by the module API then translations are generally accessible with `this.t("my string")`. +This is a shortcut to `this.moduleApi.translateString()` which in turn calls into the translation engine at runtime to +determine which appropriately-translated string should be returned. + +### Opening dialogs + +Dialogs are opened through the `openDialog()` function on a `ModuleApi` instance. They accept a return model, component +properties definition, and a dialog component type. The dialog component itself must extend `DialogContent<>` from +the module API in order to open correctly. + +The dialog component overrides `trySubmit()` and returns a promise for the return model, which is then passed back through +to the promise returned by `openDialog()`. + +The `DialogContent<>` component is supplied with supporting components at the react-sdk layer to make dialog handling +generic: all a module needs to do is supply the content that goes into the dialog. + +### Using standard UI elements + +The react-sdk provides a number of components for building Matrix clients as well as some supporting components to make +it easier to have standardized styles on things like text inputs. Modules are naturally interested in these components +so their UI looks nearly indistinguishable from the rest of the app, however the react-sdk's components are not able to +be accessed directly. + +Instead, similar to dialogs and translations, modules use a proxy component which gets replaced by the real thing at +runtime. For example, there is a `TextInputField` component supplied by the module API which gets translated into a +decorated field at runtime for the module. + +**Note for react-sdk maintainers:** Don't forget to set the `renderFactory` of these components, otherwise the UI will +be subpar. + +### Account management + +Modules can register for an account without overriding the logged-in user's auth data with the `registerSimpleAccount()` +function on a `ModuleApi` instance. If the module would like to use that auth data, or has a different set of +authentication information in mind, it can call `overwriteAccountAuth()` on a `ModuleApi` instance to overwrite +(**without warning**) the current user's session. + +### View management + +From the `RuntimeModule` instance, modules can listen to various events that happen within the client to override +a small bit of the UI behaviour. For example, listening for `RoomViewLifecycle.PreviewRoomNotLoggedIn` allows the module +to change the behaviour of the "room preview bar" to enable future cases of `RoomViewLifecycle.JoinFromRoomPreview` +being raised for additional handling. + +The module can also change what room/user/entity the user is looking at, and join it (if it's a room), with +`navigatePermalink` on a `ModuleApi` instance. + +## Contributing / developing + +Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for the mechanics of the contribution process. + +For development, it is recommended to set up a normal element-web development environment and `yarn link` the +module API into both the react-sdk and element-web layers. + +Visit [#element-dev:matrix.org](https://matrix.to/#/#element-dev:matrix.org) for support with getting a development +environment going. + +## Releases + +Because this is a scoped package, it needs to be published in a special way: + +```bash +npm publish --access public +``` diff --git a/package.json b/package.json index e442fb5..36ee448 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "clean": "rimraf lib", "build": "yarn clean && yarn build:compile && yarn build:types", "build:types": "tsc -p ./tsconfig.build.json --emitDeclarationOnly", - "build:compile": "babel -d lib --verbose --extensions \".ts\" src", + "build:compile": "babel -d lib --verbose --extensions \".ts,.tsx\" src", "start": "tsc -p ./tsconfig.build.json -w", "test": "jest", "lint": "eslint src test && tsc --noEmit", @@ -30,9 +30,12 @@ "@babel/eslint-parser": "^7.17.0", "@babel/eslint-plugin": "^7.17.7", "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-transform-runtime": "^7.17.0", "@babel/preset-env": "^7.16.11", + "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", "@types/jest": "^27.4.1", + "@types/react": "^17", "@typescript-eslint/eslint-plugin": "^5.18.0", "@typescript-eslint/parser": "^5.18.0", "eslint": "^8.12.0", @@ -43,5 +46,8 @@ "rimraf": "^3.0.2", "ts-jest": "^27.1.4", "typescript": "^4.6.3" + }, + "dependencies": { + "@babel/runtime": "^7.17.9" } } diff --git a/src/ModuleApi.ts b/src/ModuleApi.ts new file mode 100644 index 0000000..0a0b857 --- /dev/null +++ b/src/ModuleApi.ts @@ -0,0 +1,92 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 React from "react"; + +import { PlainSubstitution, TranslationStringsObject } from "./types/translations"; +import { DialogProps } from "./components/DialogContent"; +import { AccountAuthInfo } from "./types/AccountAuthInfo"; + +/** + * A module API surface for the react-sdk. Provides a stable API for modules to + * interact with the internals of the react-sdk without having to update themselves + * for refactorings or code changes within the react-sdk. + * + * An instance of a ModuleApi is provided to all modules at runtime. + */ +export interface ModuleApi { + /** + * Register strings with the translation engine. This supports overriding strings which + * the system is already aware of. + * @param translations The translations to load. + */ + registerTranslations(translations: TranslationStringsObject): void; + + /** + * Runs a string through the translation engine. If variables are needed, use %(varName)s + * as a placeholder for varName in the variables object. + * @param s The string. Should already be known to the engine. + * @param variables The variables to replace, if any. + * @returns The translated string. + */ + translateString(s: string, variables?: Record): string; + + /** + * Opens a dialog in the client. + * @param title The title of the dialog + * @param body The function which creates a body component for the dialog. + * @param props Optional props to provide to the dialog. + * @returns Whether the user submitted the dialog or closed it, and the model returned by the + * dialog component if submitted. + */ + openDialog( + title: string, + body: (props: P, ref: React.RefObject) => React.ReactNode, + props?: Omit, + ): Promise<{ didOkOrSubmit: boolean, model: M }>; + + /** + * Registers for an account on the currently connected homeserver. This requires that the homeserver + * offer a password-only flow without other flows. This means it is not traditionally compatible with + * homeservers like matrix.org which also generally require a combination of reCAPTCHA, email address, + * terms of service acceptance, etc. + * @param username The username to register. + * @param password The password to register. + * @param displayName Optional display name to set. + * @returns Resolves to the authentication info for the created account. + */ + registerSimpleAccount(username: string, password: string, displayName?: string): Promise; + + /** + * Switches the user's currently logged-in account to the one specified. The user will not + * be warned. + * @param accountAuthInfo The authentication info to log in with. + * @returns Resolves when complete. + */ + overwriteAccountAuth(accountAuthInfo: AccountAuthInfo): Promise; + + /** + * Switches the user's current view to look at the given permalink. If the permalink is + * a room, it can optionally be joined automatically if required. + * + * Permalink must be a matrix.to permalink at this time. + * @param uri The URI to navigate to. + * @param andJoin True to also join the room if needed. Does nothing if the link isn't to + * a room. + * @returns Resolves when complete. + */ + navigatePermalink(uri: string, andJoin?: boolean): Promise; +} diff --git a/src/RuntimeModule.ts b/src/RuntimeModule.ts new file mode 100644 index 0000000..704561f --- /dev/null +++ b/src/RuntimeModule.ts @@ -0,0 +1,44 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 { EventEmitter } from "events"; + +import { ModuleApi } from "./ModuleApi"; +import { PlainSubstitution } from "./types/translations"; + +// TODO: Type the event emitter with AnyLifecycle (extract TypedEventEmitter from js-sdk somehow?) +// See https://github.com/matrix-org/matrix-react-sdk-module-api/issues/4 + +/** + * Represents a module which is loaded at runtime. Modules which implement this class + * will be provided information about the application state and can react to it. + */ +export abstract class RuntimeModule extends EventEmitter { + protected constructor(protected readonly moduleApi: ModuleApi) { + super(); + } + + /** + * Run a string through the translation engine. Shortcut to ModuleApi#translateString(). + * @param s The string. + * @param variables The variables, if any. + * @returns The translated string. + * @protected + */ + protected t(s: string, variables?: Record): string { + return this.moduleApi.translateString(s, variables); + } +} diff --git a/src/components/DialogContent.tsx b/src/components/DialogContent.tsx new file mode 100644 index 0000000..cf3152e --- /dev/null +++ b/src/components/DialogContent.tsx @@ -0,0 +1,62 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 * as React from "react"; +import { ModuleApi } from "../ModuleApi"; +import { PlainSubstitution } from "../types/translations"; + +export interface DialogProps { + moduleApi: ModuleApi; +} + +export interface DialogState { + busy: boolean; + error?: string; +} + +export abstract class DialogContent

+ extends React.PureComponent { + + protected constructor(props: P, state?: S) { + super(props); + + this.state = { + busy: false, + ...state, + }; + } + + /** + * Run a string through the translation engine. Shortcut to ModuleApi#translateString(). + * @param s The string. + * @param variables The variables, if any. + * @returns The translated string. + * @protected + */ + protected t(s: string, variables?: Record): string { + return this.props.moduleApi.translateString(s, variables); + } + + /** + * Called when the dialog is submitted. Note that calling this will not submit the + * dialog by default - this component will be wrapped in a form which handles keyboard + * submission and buttons on its own. + * + * If the returned promise resolves then the dialog will be closed, otherwise the dialog + * will stay open. + */ + public abstract trySubmit(): Promise; +} diff --git a/src/components/Spinner.tsx b/src/components/Spinner.tsx new file mode 100644 index 0000000..1e599ad --- /dev/null +++ b/src/components/Spinner.tsx @@ -0,0 +1,29 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 * as React from "react"; + +export class Spinner extends React.PureComponent { + /** + * The factory this component uses to render itself. Set to a different value to override. + * @returns The component, rendered. + */ + public static renderFactory = (): React.ReactNode => null; + + public render() { + return Spinner.renderFactory(); + } +} diff --git a/src/components/TextInputField.tsx b/src/components/TextInputField.tsx new file mode 100644 index 0000000..fcf5fb2 --- /dev/null +++ b/src/components/TextInputField.tsx @@ -0,0 +1,41 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 * as React from "react"; + +export interface TextInputFieldProps { + label: string; + value: string; + onChange: (newValue: string) => void; +} + +export class TextInputField extends React.PureComponent { + /** + * The factory this component uses to render itself. Set to a different value to override. + * @param props The component properties + * @returns The component, rendered. + */ + public static renderFactory = (props: TextInputFieldProps): React.ReactNode => ( + + ); + + public render() { + return TextInputField.renderFactory(this.props); + } +} diff --git a/src/lifecycles/RoomViewLifecycle.ts b/src/lifecycles/RoomViewLifecycle.ts new file mode 100644 index 0000000..1fe46ad --- /dev/null +++ b/src/lifecycles/RoomViewLifecycle.ts @@ -0,0 +1,28 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 enum RoomViewLifecycle { + PreviewRoomNotLoggedIn = "preview_not_logged_in", + JoinFromRoomPreview = "try_join_not_logged_in", +} + +export type RoomPreviewOpts = { + canJoin: boolean; +}; + +export type RoomPreviewListener = (opts: RoomPreviewOpts, roomId: string) => void; + +export type JoinFromPreviewListener = (roomId: string) => void; diff --git a/src/lifecycles/types.ts b/src/lifecycles/types.ts new file mode 100644 index 0000000..3f0a98e --- /dev/null +++ b/src/lifecycles/types.ts @@ -0,0 +1,21 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 { RoomViewLifecycle } from "./RoomViewLifecycle"; + +export type AnyLifecycle = + | RoomViewLifecycle + ; diff --git a/src/types/AccountAuthInfo.ts b/src/types/AccountAuthInfo.ts new file mode 100644 index 0000000..9e68f1e --- /dev/null +++ b/src/types/AccountAuthInfo.ts @@ -0,0 +1,37 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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. +*/ + +/** + * Matrix account authentication information for a known user. + */ +export interface AccountAuthInfo { + /** + * The user ID. + */ + userId: string; + /** + * The device ID. + */ + deviceId: string; + /** + * The access token belonging to this device ID and user ID. + */ + accessToken: string; + /** + * The homeserver URL where the credentials are valid. + */ + homeserverUrl: string; +} diff --git a/src/types/translations.ts b/src/types/translations.ts new file mode 100644 index 0000000..bb41ccd --- /dev/null +++ b/src/types/translations.ts @@ -0,0 +1,31 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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. +*/ + +/** + * Translations object mapping an input string to language variants. + * Mirrors custom translations support introduced by the react-sdk + * here: https://github.com/matrix-org/matrix-react-sdk/pull/7886 + */ +export type TranslationStringsObject = { + [str: string]: { + [lang: string]: string; + }; +}; + +/** + * Represents a simple translation replacement (non-component replacement) + */ +export type PlainSubstitution = number | string; diff --git a/test/placeholder.test.ts b/test/placeholder.test.ts new file mode 100644 index 0000000..b19edf4 --- /dev/null +++ b/test/placeholder.test.ts @@ -0,0 +1,24 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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. +*/ + +// We don't have anything which needs tests at the moment, so stub out a test +// to appease the linter's requirements. + +describe("placeholder", () => { + it('should pass the linter', () => { + // nothing to do. + }); +}); diff --git a/tsconfig.build.json b/tsconfig.build.json index eccb5a2..080e76e 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -7,9 +7,11 @@ "module": "commonjs", "emitDecoratorMetadata": true, "declaration": true, - "outDir": "./lib" + "outDir": "./lib", + "jsx": "react" }, "include": [ - "./src/**/*.ts" + "./src/**/*.ts", + "./src/**/*.tsx" ] } diff --git a/tsconfig.json b/tsconfig.json index 8db086b..b52c58b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,10 +7,12 @@ "moduleResolution": "node", "noImplicitAny": true, "declaration": false, - "noEmit": true + "noEmit": true, + "jsx": "react" }, "include": [ "./src/**/*.ts", + "./src/**/*.tsx", "./test/**/*.ts" ] } diff --git a/yarn.lock b/yarn.lock index fdf301f..737f13e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -505,6 +505,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" + integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -753,6 +760,39 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-react-display-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" + integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-jsx-development@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" + integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.16.7" + +"@babel/plugin-transform-react-jsx@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" + integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.16.7" + "@babel/types" "^7.17.0" + +"@babel/plugin-transform-react-pure-annotations@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" + integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-transform-regenerator@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" @@ -767,6 +807,18 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-runtime@^7.17.0": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz#0a2e08b5e2b2d95c4b1d3b3371a2180617455b70" + integrity sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + semver "^6.3.0" + "@babel/plugin-transform-shorthand-properties@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" @@ -918,6 +970,18 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-react@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" + integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-react-display-name" "^7.16.7" + "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/plugin-transform-react-jsx-development" "^7.16.7" + "@babel/plugin-transform-react-pure-annotations" "^7.16.7" + "@babel/preset-typescript@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" @@ -927,6 +991,13 @@ "@babel/helper-validator-option" "^7.16.7" "@babel/plugin-transform-typescript" "^7.16.7" +"@babel/runtime@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" + integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.8.4": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" @@ -1336,6 +1407,25 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== +"@types/prop-types@*": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + +"@types/react@^17": + version "17.0.43" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55" + integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -1892,6 +1982,11 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" +csstype@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"