chore: update react imports

Signed-off-by: Paul Schultz <pschultz@pobox.com>
This commit is contained in:
Paul Schultz
2025-01-28 10:21:17 -06:00
parent 02981a2377
commit 2e26579e06
1282 changed files with 2776 additions and 3434 deletions
+12
View File
@@ -20,6 +20,7 @@ module.exports = {
root: true,
plugins: ['@spotify', 'notice', 'react', 'testing-library'],
rules: {
'react/react-in-jsx-scope': 'off',
'notice/notice': [
'error',
{
@@ -47,6 +48,17 @@ module.exports = {
selector:
"CallExpression[arguments.length=0] > MemberExpression[property.name='toUpperCase']",
},
{
message: "Default React import not allowed.",
selector:
"ImportDeclaration[source.value='react'][specifiers.0.type='ImportDefaultSpecifier']",
},
{
message:
"Default React import not allowed. If you need a global type that collides with a React named export (such as `MouseEvent`), try using `globalThis.MouseHandler`.",
selector:
"ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
},
],
'testing-library/await-async-queries': 'error',
'testing-library/await-async-utils': 'error',
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import styles from './styles.module.css';
export const Banner = ({
+2 -2
View File
@@ -14,14 +14,14 @@
* limitations under the License.
*/
import React from 'react';
import { ReactNode } from 'react';
import styles from './styles.module.css';
export const Chip = ({
children,
head = false,
}: {
children: React.ReactNode;
children: ReactNode;
head?: boolean;
}) => {
return (
@@ -14,14 +14,14 @@
* limitations under the License.
*/
import React from 'react';
import { ReactNode, CSSProperties } from 'react';
export const Columns = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
children: ReactNode;
style?: CSSProperties;
}) => {
return (
<div className="columns" style={style}>
@@ -1,4 +1,3 @@
import React from 'react';
import { BoxSvg } from './svgs/box';
import { FlexSvg } from './svgs/flex';
import { GridSvg } from './svgs/grid';
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const BoxSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const ContainerSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const FlexSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const GridSvg = () => {
return (
<svg
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
export const InlineSvg = () => {
return (
<svg
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { RoadmapItem } from './list';
export const Roadmap = ({ list }: { list: RoadmapItem[] }) => {
+10 -10
View File
@@ -1,7 +1,7 @@
import React from 'react';
import { CSSProperties, ReactNode } from 'react';
import styles from './styles.module.css';
export const Root = ({ children }: { children: React.ReactNode }) => {
export const Root = ({ children }: { children: ReactNode }) => {
return (
<div className={styles.wrapper}>
<table className={styles.table}>{children}</table>
@@ -9,15 +9,15 @@ export const Root = ({ children }: { children: React.ReactNode }) => {
);
};
export const Header = ({ children }: { children: React.ReactNode }) => {
export const Header = ({ children }: { children: ReactNode }) => {
return <thead>{children}</thead>;
};
export const Body = ({ children }: { children: React.ReactNode }) => {
export const Body = ({ children }: { children: ReactNode }) => {
return <tbody>{children}</tbody>;
};
export const HeaderRow = ({ children }: { children: React.ReactNode }) => {
export const HeaderRow = ({ children }: { children: ReactNode }) => {
return <tr>{children}</tr>;
};
@@ -25,8 +25,8 @@ export const HeaderCell = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
children: ReactNode;
style?: CSSProperties;
}) => {
return (
<th
@@ -38,7 +38,7 @@ export const HeaderCell = ({
);
};
export const Row = ({ children }: { children: React.ReactNode }) => {
export const Row = ({ children }: { children: ReactNode }) => {
return <tr className={styles.tableRow}>{children}</tr>;
};
@@ -46,8 +46,8 @@ export const Cell = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
children: ReactNode;
style?: CSSProperties;
}) => {
return (
<td className={styles.tableCell} style={style}>
+2 -2
View File
@@ -1,4 +1,4 @@
import React, { ReactNode } from 'react';
import { isValidElement, ReactNode } from 'react';
import type { MDXComponents } from 'mdx/types';
import Image, { ImageProps } from 'next/image';
import { CodeBlock } from '@/components/CodeBlock';
@@ -28,7 +28,7 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
<li className={styles.li}>{children as ReactNode}</li>
),
pre: ({ children }) => {
const codeContent = React.isValidElement(children)
const codeContent = isValidElement(children)
? (children.props as { children: string }).children
: '';
+1 -1
View File
@@ -1,4 +1,4 @@
import React, {
import {
createContext,
useContext,
ReactNode,
@@ -55,15 +55,15 @@ When using ALB authentication Backstage will only be loaded once the user has su
- add the following definition just before the app is created (`const app = createApp`):
```ts
import React from 'react';
import { useState, useEffect } from 'react';
import { UserIdentity } from '@backstage/core-components';
import { SignInPageProps } from '@backstage/core-app-api';
import { useApi, configApiRef } from '@backstage/core-plugin-api';
const SampleSignInComponent: any = (props: SignInPageProps) => {
const [error, setError] = React.useState<string | undefined>();
const [error, setError] = useState<string | undefined>();
const config = useApi(configApiRef);
React.useEffect(() => {
useEffect(() => {
const shouldAuth = !!config.getOptionalConfig('auth.providers.awsalb');
if (shouldAuth) {
fetch(`${window.location.origin}/api/auth/awsalb/refresh`)
@@ -3,7 +3,6 @@
ExampleComponent.tsx reference
```tsx
import React from 'react';
import { Typography, Grid } from '@material-ui/core';
import { identityApiRef, useApi } from '@backstage/core-plugin-api';
import {
@@ -3,7 +3,6 @@
ExampleFetchComponent.tsx reference
```tsx
import React from 'react';
import useAsync from 'react-use/lib/useAsync';
import Alert from '@material-ui/lab/Alert';
import { githubAuthApiRef, useApi } from '@backstage/core-plugin-api';
@@ -1,7 +1,6 @@
ConfluenceResultListItem.tsx reference
```tsx
import React from 'react';
import { Link } from '@backstage/core-components';
import { IndexableDocument } from '@backstage/plugin-search-common';
import {
-1
View File
@@ -37,7 +37,6 @@ components. For example, the
[`ErrorApi`](../reference/core-plugin-api.errorapi.md) can be accessed like this:
```tsx
import React from 'react';
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
export const MyComponent = () => {
-1
View File
@@ -24,7 +24,6 @@ Create a new `packages/app/src/components/search/SearchPage.tsx` file in your
Backstage app with the following contents:
```tsx
import React from 'react';
import { Content, Header, Page } from '@backstage/core-components';
import { Grid, List, Card, CardContent } from '@material-ui/core';
import {
-4
View File
@@ -242,8 +242,6 @@ which renderers to use. Note that the order of the renderers matters! The first
Here is an example of customizing your `SearchPage`:
```tsx title="packages/app/src/components/searchPage.tsx"
import React from 'react';
import { Grid, Paper } from '@material-ui/core';
import BuildIcon from '@material-ui/icons/Build';
@@ -325,8 +323,6 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
Assuming you have completely customized your SearchModal, here's an example that renders results with extensions:
```tsx title="packages/app/src/components/searchModal.tsx"
import React from 'react';
import { DialogContent, DialogTitle, Paper } from '@material-ui/core';
import BuildIcon from '@material-ui/icons/Build';
@@ -442,7 +442,6 @@ import {
EntityTypePicker,
UserListPicker,
} from '@backstage/plugin-catalog-react';
import React from 'react';
export const CustomCatalogPage = () => {
const orgName =
@@ -29,7 +29,6 @@ As an example, we will create a component that validates whether a string is in
```tsx
//packages/app/src/scaffolder/ValidateKebabCase/ValidateKebabCaseExtension.tsx
import React from 'react';
import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react';
import type { FieldValidation } from '@rjsf/utils';
import FormControl from '@material-ui/core/FormControl';
@@ -18,8 +18,7 @@ This is the same [field](https://rjsf-team.github.io/react-jsonschema-form/docs/
The [createScaffolderLayout](https://backstage.io/docs/reference/plugin-scaffolder-react.createscaffolderlayout) function is used to mark a component as a custom step layout:
```ts
import React from 'react';
```tsx
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
import {
createScaffolderLayout,
+1 -2
View File
@@ -181,8 +181,7 @@ provided by the Addon framework.
```tsx
// plugins/your-plugin/src/addons/MakeAllImagesCatGifs.tsx
import React, { useEffect } from 'react';
import { useEffect } from 'react';
import { useShadowRootElements } from '@backstage/plugin-techdocs-react';
// This is a normal react component; in order to make it an Addon, you would
+5 -4
View File
@@ -135,6 +135,7 @@ You can easily customize the TechDocs home page using TechDocs panel layout
Modify your `App.tsx` as follows:
```tsx
import { Fragment, PropsWithChildren } from 'react';
import { TechDocsCustomHome } from '@backstage/plugin-techdocs';
//...
@@ -175,7 +176,7 @@ const techDocsTabsConfig = [
filterPredicate: filterEntity,
panelType: 'TechDocsIndexPage',
title: 'All',
panelProps: { PageWrapper: React.Fragment, CustomHeader: React.Fragment, options: options },
panelProps: { PageWrapper: Fragment, CustomHeader: Fragment, options: options },
},
],
},
@@ -184,7 +185,7 @@ const docsFilter = {
kind: ['Location', 'Resource', 'Component'],
'metadata.annotations.featured-docs': CATALOG_FILTER_EXISTS,
}
const customPageWrapper = ({ children }: React.PropsWithChildren<{}>) =>
const customPageWrapper = ({ children }: PropsWithChildren<{}>) =>
(<PageWithHeader title="Docs" themeId="documentation">{children}</PageWithHeader>)
const AppRoutes = () => {
<FlatRoutes>
@@ -212,7 +213,7 @@ maintain such a component in a new directory at
For example, you can define the following Custom home page component:
```tsx
import React from 'react';
import { ReactNode } from 'react';
import { Content } from '@backstage/core-components';
import {
@@ -232,7 +233,7 @@ import { EntityListDocsGrid } from '@backstage/plugin-techdocs';
export type CustomTechDocsHomeProps = {
groups?: Array<{
title: React.ReactNode;
title: ReactNode;
filterPredicate: ((entity: Entity) => boolean) | string;
}>;
};
@@ -40,7 +40,6 @@ Route refs do not have any behavior themselves. They are an opaque value that re
The code snippet in the previous section does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension:
```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createFrontendPlugin,
createPageExtension,
@@ -91,7 +90,6 @@ Route references can be used to link to page in the same plugin, or to pages in
Suppose we are creating a plugin that renders a Catalog index page with a link to a "Foo" component details page. Here is the code for the index page:
```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { useRouteRef } from '@backstage/frontend-plugin-api';
import { detailsRouteRef } from '../routes';
@@ -125,7 +123,6 @@ We use the `useRouteRef` hook to create a link generator function that returns t
Let's see how the details page can get the parameters from the URL:
```tsx title="plugins/catalog/src/components/DetailsPage.tsx"
import React from 'react';
import { useRouteRefParams } from '@backstage/frontend-plugin-api';
import { detailsRouteRef } from '../routes';
@@ -169,7 +166,6 @@ export const createComponentExternalRouteRef = createExternalRouteRef();
External routes are also used in a similar way as regular routes:
```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { useRouteRef } from '@backstage/frontend-plugin-api';
import { createComponentExternalRouteRef } from '../routes';
@@ -194,7 +190,6 @@ Given the above binding, using `useRouteRef(createComponentExternalRouteRef)` wi
Now the only thing left is to provide the page and external route via a plugin:
```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createFrontendPlugin,
createPageExtension,
@@ -333,7 +328,6 @@ export const detailsSubRouteRef = createSubRouteRef({
Using subroutes in a page extension is as simple as this:
```tsx title="plugins/catalog/src/components/IndexPage.tsx"
import React from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import { useRouteRef } from '@backstage/frontend-plugin-api';
import { indexRouteRef, detailsSubRouteRef } from '../routes';
@@ -381,7 +375,6 @@ export const IndexPage = () => {
This is how you can get the parameters of a sub route URL:
```tsx title="plugins/catalog/src/components/DetailsPage.tsx"
import React from 'react';
import { useParams } from 'react-router-dom';
export const DetailsPage = () => {
@@ -405,7 +398,6 @@ export const DetailsPage = () => {
Finally, see how a plugin can provide subroutes:
```tsx title="plugins/catalog/src/plugin.tsx"
import React from 'react';
import {
createFrontendPlugin,
createPageExtension,
@@ -86,7 +86,6 @@ There is one more detail that we need to deal with before moving on. The `app.cr
```tsx title="in packages/app/src/index.tsx"
import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom/client';
// highlight-remove-next-line
import App from './App';
@@ -25,7 +25,6 @@ A component can be used for more than one extension, and it should be tested ind
Use the `renderInTestApp` helper to render a given component inside a Backstage test app:
```tsx
import React from 'react';
import { screen } from '@testing-library/react';
import { renderInTestApp } from '@backstage/frontend-test-utils';
import { EntityDetails } from './plugin';
@@ -44,7 +43,6 @@ describe('Entity details component', () => {
To mock [Utility APIs](../architecture/33-utility-apis.md) that are used by your component you can use the `TestApiProvider` to override individual API implementations. In the snippet below, we wrap the component within a `TestApiProvider` in order to mock the catalog client API:
```tsx
import React from 'react';
import { screen } from '@testing-library/react';
import {
renderInTestApp,
-2
View File
@@ -416,8 +416,6 @@ In your front-end application, locate the `src` folder. We suggest creating the
```tsx title="customIcons.tsx"
import { SvgIcon, SvgIconProps } from '@material-ui/core';
import React from 'react';
export const ExampleIcon = (props: SvgIconProps) => (
<SvgIcon {...props} viewBox="0 0 24 24">
<path
-3
View File
@@ -37,8 +37,6 @@ yarn --cwd packages/app add @backstage/plugin-home
Inside your `packages/app` directory, create a new file where our new homepage component is going to live. Create `packages/app/src/components/home/HomePage.tsx` with the following initial code
```tsx
import React from 'react';
export const HomePage = () => (
/* We will shortly compose a pretty homepage here. */
<h1>Welcome to Backstage!</h1>
@@ -156,7 +154,6 @@ contribute, check the
> [Contributing documentation](https://github.com/backstage/backstage/blob/master/plugins/home/README.md#contributing)
```tsx
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { HomePageCompanyLogo } from '@backstage/plugin-home';
-1
View File
@@ -32,7 +32,6 @@ With that, Backstage's cli and backend will detect public entry point and serve
2. This file is the public entry point for your application, and it should only contain what unauthenticated users should see:
```tsx title="in packages/app/src/index-public-experimental.tsx"
import React from 'react';
import ReactDOM from 'react-dom/client';
import { createApp } from '@backstage/app-defaults';
import { AppRouter } from '@backstage/core-app-api';
-1
View File
@@ -134,7 +134,6 @@ changes, let's start by wiping this component clean.
1. Replace everything in the file with the following:
```tsx
import React from 'react';
import useAsync from 'react-use/lib/useAsync';
import Alert from '@material-ui/lab/Alert';
import { Table, TableColumn, Progress } from '@backstage/core-components';
-1
View File
@@ -50,7 +50,6 @@ To switch a project to React 18, there are generally three changes that need to
```tsx title="packages/app/src/index.tsx"
import '@backstage/cli/asset-types';
import React from 'react';
// highlight-remove-next-line
import ReactDOM from 'react-dom';
// highlight-add-next-line
+1 -1
View File
@@ -16,7 +16,7 @@
import { screen } from '@testing-library/react';
import { renderWithEffects } from '@backstage/test-utils';
import React, { PropsWithChildren } from 'react';
import { PropsWithChildren } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { createApp } from './createApp';
@@ -15,7 +15,6 @@
*/
import { render, screen } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { OptionallyWrapInRouter } from './components';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { ReactNode } from 'react';
import { ReactNode } from 'react';
import Button from '@material-ui/core/Button';
import { ErrorPanel, Progress, ErrorPage } from '@backstage/core-components';
import {
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import {
UnifiedThemeProvider,
themes as builtinThemes,
@@ -14,8 +14,6 @@
* limitations under the License.
*/
import React from 'react';
export const Component = () => (
<div>
<h1>SHIP IT!</h1>
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { SidebarItem } from '@backstage/core-components';
import SaveIcon from '@material-ui/icons/Save';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import {
PageBlueprint,
createFrontendPlugin,
-1
View File
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { createApp } from '@backstage/frontend-defaults';
import { pagesPlugin } from './examples/pagesPlugin';
import notFoundErrorPage from './examples/notFoundErrorPageExtension';
-1
View File
@@ -27,7 +27,6 @@ import {
WelcomeTitle,
} from '@backstage/plugin-home';
import { Content, Header, Page } from '@backstage/core-components';
import React from 'react';
import HomeIcon from '@material-ui/icons/Home';
const clockConfigs: ClockConfig[] = [
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import {
createComponentExtension,
coreComponentRefs,
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { Link } from '@backstage/core-components';
import {
createFrontendPlugin,
-1
View File
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import App from './App';
-1
View File
@@ -63,7 +63,6 @@ import {
} from '@backstage/plugin-user-settings';
import { AdvancedSettings } from './components/advancedSettings';
import AlarmIcon from '@material-ui/icons/Alarm';
import React from 'react';
import { Navigate, Route } from 'react-router-dom';
import { apis } from './apis';
import { entityPage } from './components/catalog/EntityPage';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles({
@@ -16,7 +16,6 @@
// @ts-check
// NOTE: This file is intentionally .jsx, so that there is one file in this repo where we make sure .jsx files work.
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles({
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { PropsWithChildren } from 'react';
import { PropsWithChildren } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import HomeIcon from '@material-ui/icons/Home';
import RuleIcon from '@material-ui/icons/AssignmentTurnedIn';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import { ChangeEvent } from 'react';
import { InfoCard } from '@backstage/core-components';
import List from '@material-ui/core/List';
import Grid from '@material-ui/core/Grid';
@@ -30,7 +30,7 @@ export function AdvancedSettings() {
'off',
);
const toggleValue = (ev: React.ChangeEvent<HTMLInputElement>) => {
const toggleValue = (ev: ChangeEvent<HTMLInputElement>) => {
setValue(ev.currentTarget.checked ? 'on' : 'off');
};
@@ -26,7 +26,6 @@ import {
renderInTestApp,
TestApiProvider,
} from '@backstage/test-utils';
import React from 'react';
import { cicdContent } from './EntityPage';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
@@ -72,7 +72,7 @@ import {
} from '@backstage/plugin-org';
import Button from '@material-ui/core/Button';
import Grid from '@material-ui/core/Grid';
import React, { ReactNode } from 'react';
import { ReactNode } from 'react';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import {
TextSize,
@@ -20,7 +20,6 @@ import {
InfoContent,
} from '@backstage/plugin-devtools';
import { DevToolsLayout } from '@backstage/plugin-devtools';
import React from 'react';
import { UnprocessedEntitiesContent } from '@backstage/plugin-catalog-unprocessed-entities';
const DevToolsPage = () => {
@@ -28,7 +28,6 @@ import {
} from '@backstage/plugin-home';
import { Content, Header, Page } from '@backstage/core-components';
import { HomePageSearchBar } from '@backstage/plugin-search';
import React from 'react';
import HomeIcon from '@material-ui/icons/Home';
const clockConfigs: ClockConfig[] = [
@@ -1,148 +1,148 @@
/*
* Copyright 2023 The Backstage Authors
*
* 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 {
HomePageStarredEntities,
HomePageRandomJoke,
CustomHomepageGrid,
} from '@backstage/plugin-home';
import {
starredEntitiesApiRef,
MockStarredEntitiesApi,
entityRouteRef,
catalogApiRef,
} from '@backstage/plugin-catalog-react';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/config';
import { searchApiRef } from '@backstage/plugin-search-react';
import { HomePageSearchBar, searchPlugin } from '@backstage/plugin-search';
import React, { ComponentType } from 'react';
const entities = [
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity',
title: 'Mock Starred Entity!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-2',
title: 'Mock Starred Entity 2!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-3',
title: 'Mock Starred Entity 3!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-4',
title: 'Mock Starred Entity 4!',
},
},
];
const catalogApi = catalogApiMock({ entities });
const starredEntitiesApi = new MockStarredEntitiesApi();
starredEntitiesApi.toggleStarred('component:default/example-starred-entity');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-2');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-3');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-4');
export default {
title: 'Plugins/Home/Templates',
decorators: [
(Story: ComponentType<{}>) =>
wrapInTestApp(
<>
<TestApiProvider
apis={[
[catalogApiRef, catalogApi],
[starredEntitiesApiRef, starredEntitiesApi],
[searchApiRef, { query: () => Promise.resolve({ results: [] }) }],
[
configApiRef,
new ConfigReader({
backend: {
baseUrl: 'https://localhost:7007',
},
}),
],
]}
>
<Story />
</TestApiProvider>
</>,
{
mountedRoutes: {
'/hello-company': searchPlugin.routes.root,
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
],
};
export const CustomizableTemplate = () => {
// This is the default configuration that is shown to the user
// when first arriving to the homepage.
const defaultConfig = [
{
component: 'HomePageSearchBar',
x: 0,
y: 0,
width: 12,
height: 5,
},
{
component: 'HomePageRandomJoke',
x: 0,
y: 2,
width: 6,
height: 16,
},
{
component: 'HomePageStarredEntities',
x: 6,
y: 2,
width: 6,
height: 12,
},
];
return (
<CustomHomepageGrid config={defaultConfig} rowHeight={10}>
// Insert the allowed widgets inside the grid. User can add, organize and
// remove the widgets as they want.
<HomePageSearchBar />
<HomePageRandomJoke />
<HomePageStarredEntities />
</CustomHomepageGrid>
);
};
/*
* Copyright 2023 The Backstage Authors
*
* 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 {
HomePageStarredEntities,
HomePageRandomJoke,
CustomHomepageGrid,
} from '@backstage/plugin-home';
import {
starredEntitiesApiRef,
MockStarredEntitiesApi,
entityRouteRef,
catalogApiRef,
} from '@backstage/plugin-catalog-react';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/config';
import { searchApiRef } from '@backstage/plugin-search-react';
import { HomePageSearchBar, searchPlugin } from '@backstage/plugin-search';
import { ComponentType } from 'react';
const entities = [
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity',
title: 'Mock Starred Entity!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-2',
title: 'Mock Starred Entity 2!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-3',
title: 'Mock Starred Entity 3!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-4',
title: 'Mock Starred Entity 4!',
},
},
];
const catalogApi = catalogApiMock({ entities });
const starredEntitiesApi = new MockStarredEntitiesApi();
starredEntitiesApi.toggleStarred('component:default/example-starred-entity');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-2');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-3');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-4');
export default {
title: 'Plugins/Home/Templates',
decorators: [
(Story: ComponentType<{}>) =>
wrapInTestApp(
<>
<TestApiProvider
apis={[
[catalogApiRef, catalogApi],
[starredEntitiesApiRef, starredEntitiesApi],
[searchApiRef, { query: () => Promise.resolve({ results: [] }) }],
[
configApiRef,
new ConfigReader({
backend: {
baseUrl: 'https://localhost:7007',
},
}),
],
]}
>
<Story />
</TestApiProvider>
</>,
{
mountedRoutes: {
'/hello-company': searchPlugin.routes.root,
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
],
};
export const CustomizableTemplate = () => {
// This is the default configuration that is shown to the user
// when first arriving to the homepage.
const defaultConfig = [
{
component: 'HomePageSearchBar',
x: 0,
y: 0,
width: 12,
height: 5,
},
{
component: 'HomePageRandomJoke',
x: 0,
y: 2,
width: 6,
height: 16,
},
{
component: 'HomePageStarredEntities',
x: 6,
y: 2,
width: 6,
height: 12,
},
];
return (
<CustomHomepageGrid config={defaultConfig} rowHeight={10}>
// Insert the allowed widgets inside the grid. User can add, organize and
// remove the widgets as they want.
<HomePageSearchBar />
<HomePageRandomJoke />
<HomePageStarredEntities />
</CustomHomepageGrid>
);
};
@@ -1,196 +1,196 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 {
HomePageToolkit,
HomePageCompanyLogo,
HomePageStarredEntities,
TemplateBackstageLogo,
TemplateBackstageLogoIcon,
} from '@backstage/plugin-home';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { Content, Page, InfoCard } from '@backstage/core-components';
import {
starredEntitiesApiRef,
MockStarredEntitiesApi,
entityRouteRef,
catalogApiRef,
} from '@backstage/plugin-catalog-react';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/config';
import { HomePageSearchBar, searchPlugin } from '@backstage/plugin-search';
import {
searchApiRef,
SearchContextProvider,
} from '@backstage/plugin-search-react';
import Grid from '@material-ui/core/Grid';
import { makeStyles } from '@material-ui/core/styles';
import React, { ComponentType, PropsWithChildren } from 'react';
const entities = [
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity',
title: 'Mock Starred Entity!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-2',
title: 'Mock Starred Entity 2!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-3',
title: 'Mock Starred Entity 3!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-4',
title: 'Mock Starred Entity 4!',
},
},
];
const catalogApi = catalogApiMock({ entities });
const starredEntitiesApi = new MockStarredEntitiesApi();
starredEntitiesApi.toggleStarred('component:default/example-starred-entity');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-2');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-3');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-4');
export default {
title: 'Plugins/Home/Templates',
decorators: [
(Story: ComponentType<PropsWithChildren<{}>>) =>
wrapInTestApp(
<>
<TestApiProvider
apis={[
[catalogApiRef, catalogApi],
[starredEntitiesApiRef, starredEntitiesApi],
[searchApiRef, { query: () => Promise.resolve({ results: [] }) }],
[
configApiRef,
new ConfigReader({
stackoverflow: {
baseUrl: 'https://api.stackexchange.com/2.2',
},
}),
],
]}
>
<Story />
</TestApiProvider>
</>,
{
mountedRoutes: {
'/hello-company': searchPlugin.routes.root,
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
],
};
const useStyles = makeStyles(theme => ({
searchBarInput: {
maxWidth: '60vw',
margin: 'auto',
backgroundColor: theme.palette.background.paper,
borderRadius: '50px',
boxShadow: theme.shadows[1],
},
searchBarOutline: {
borderStyle: 'none',
},
}));
const useLogoStyles = makeStyles(theme => ({
container: {
margin: theme.spacing(5, 0),
},
svg: {
width: 'auto',
height: 100,
},
path: {
fill: '#7df3e1',
},
}));
export const DefaultTemplate = () => {
const classes = useStyles();
const { svg, path, container } = useLogoStyles();
return (
<SearchContextProvider>
<Page themeId="home">
<Content>
<Grid container justifyContent="center" spacing={6}>
<HomePageCompanyLogo
className={container}
logo={<TemplateBackstageLogo classes={{ svg, path }} />}
/>
<Grid container item xs={12} justifyContent="center">
<HomePageSearchBar
InputProps={{
classes: {
root: classes.searchBarInput,
notchedOutline: classes.searchBarOutline,
},
}}
placeholder="Search"
/>
</Grid>
<Grid container item xs={12}>
<Grid item xs={12} md={6}>
<HomePageStarredEntities />
</Grid>
<Grid item xs={12} md={6}>
<HomePageToolkit
tools={Array(8).fill({
url: '#',
label: 'link',
icon: <TemplateBackstageLogoIcon />,
})}
/>
</Grid>
<Grid item xs={12} md={6}>
<InfoCard title="Composable Section">
{/* placeholder for content */}
<div style={{ height: 370 }} />
</InfoCard>
</Grid>
</Grid>
</Grid>
</Content>
</Page>
</SearchContextProvider>
);
};
/*
* Copyright 2021 The Backstage Authors
*
* 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 {
HomePageToolkit,
HomePageCompanyLogo,
HomePageStarredEntities,
TemplateBackstageLogo,
TemplateBackstageLogoIcon,
} from '@backstage/plugin-home';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { Content, Page, InfoCard } from '@backstage/core-components';
import {
starredEntitiesApiRef,
MockStarredEntitiesApi,
entityRouteRef,
catalogApiRef,
} from '@backstage/plugin-catalog-react';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/config';
import { HomePageSearchBar, searchPlugin } from '@backstage/plugin-search';
import {
searchApiRef,
SearchContextProvider,
} from '@backstage/plugin-search-react';
import Grid from '@material-ui/core/Grid';
import { makeStyles } from '@material-ui/core/styles';
import { ComponentType, PropsWithChildren } from 'react';
const entities = [
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity',
title: 'Mock Starred Entity!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-2',
title: 'Mock Starred Entity 2!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-3',
title: 'Mock Starred Entity 3!',
},
},
{
apiVersion: '1',
kind: 'Component',
metadata: {
name: 'mock-starred-entity-4',
title: 'Mock Starred Entity 4!',
},
},
];
const catalogApi = catalogApiMock({ entities });
const starredEntitiesApi = new MockStarredEntitiesApi();
starredEntitiesApi.toggleStarred('component:default/example-starred-entity');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-2');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-3');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-4');
export default {
title: 'Plugins/Home/Templates',
decorators: [
(Story: ComponentType<PropsWithChildren<{}>>) =>
wrapInTestApp(
<>
<TestApiProvider
apis={[
[catalogApiRef, catalogApi],
[starredEntitiesApiRef, starredEntitiesApi],
[searchApiRef, { query: () => Promise.resolve({ results: [] }) }],
[
configApiRef,
new ConfigReader({
stackoverflow: {
baseUrl: 'https://api.stackexchange.com/2.2',
},
}),
],
]}
>
<Story />
</TestApiProvider>
</>,
{
mountedRoutes: {
'/hello-company': searchPlugin.routes.root,
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
],
};
const useStyles = makeStyles(theme => ({
searchBarInput: {
maxWidth: '60vw',
margin: 'auto',
backgroundColor: theme.palette.background.paper,
borderRadius: '50px',
boxShadow: theme.shadows[1],
},
searchBarOutline: {
borderStyle: 'none',
},
}));
const useLogoStyles = makeStyles(theme => ({
container: {
margin: theme.spacing(5, 0),
},
svg: {
width: 'auto',
height: 100,
},
path: {
fill: '#7df3e1',
},
}));
export const DefaultTemplate = () => {
const classes = useStyles();
const { svg, path, container } = useLogoStyles();
return (
<SearchContextProvider>
<Page themeId="home">
<Content>
<Grid container justifyContent="center" spacing={6}>
<HomePageCompanyLogo
className={container}
logo={<TemplateBackstageLogo classes={{ svg, path }} />}
/>
<Grid container item xs={12} justifyContent="center">
<HomePageSearchBar
InputProps={{
classes: {
root: classes.searchBarInput,
notchedOutline: classes.searchBarOutline,
},
}}
placeholder="Search"
/>
</Grid>
<Grid container item xs={12}>
<Grid item xs={12} md={6}>
<HomePageStarredEntities />
</Grid>
<Grid item xs={12} md={6}>
<HomePageToolkit
tools={Array(8).fill({
url: '#',
label: 'link',
icon: <TemplateBackstageLogoIcon />,
})}
/>
</Grid>
<Grid item xs={12} md={6}>
<InfoCard title="Composable Section">
{/* placeholder for content */}
<div style={{ height: 370 }} />
</InfoCard>
</Grid>
</Grid>
</Grid>
</Content>
</Page>
</SearchContextProvider>
);
};
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import type { FieldValidation } from '@rjsf/utils';
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
import TextField from '@material-ui/core/TextField';
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import {
createScaffolderLayout,
LayoutTemplate,
@@ -39,7 +39,7 @@ import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
import CloseIcon from '@material-ui/icons/Close';
import React, { useCallback, useEffect, useRef } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
const useStyles = makeStyles(theme => ({
@@ -42,7 +42,6 @@ import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import { Theme } from '@material-ui/core/styles/createTheme';
import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
const useStyles = makeStyles((theme: Theme) => ({
filter: {
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { Page } from '@backstage/core-components';
import {
TechDocsReaderPageHeader,
@@ -22,7 +22,6 @@ import {
SignInPage,
} from '@backstage/core-components';
import { CookieAuthRedirect } from '@backstage/plugin-auth-react';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { providers } from '../src/identityProviders';
import {
-1
View File
@@ -15,7 +15,6 @@
*/
import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@backstage/canon/css/styles.css';
-1
View File
@@ -1,4 +1,3 @@
import React from 'react';
import type { Preview, ReactRenderer } from '@storybook/react';
import { withThemeByDataAttribute } from '@storybook/addon-themes';
import '../src/css/styles.css';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import { ReactNode } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Box } from './Box';
import { Flex } from '../Flex';
@@ -67,7 +67,7 @@ export const Preview: Story = {
},
};
const CardDisplay = ({ children }: { children?: React.ReactNode }) => {
const CardDisplay = ({ children }: { children?: ReactNode }) => {
return (
<div
style={{
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
import { Flex } from '../Flex';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import { Icon } from '../Icon';
import clsx from 'clsx';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Checkbox } from './Checkbox';
import { Flex } from '../Flex';
@@ -14,14 +14,14 @@
* limitations under the License.
*/
import React from 'react';
import { forwardRef } from 'react';
import { Checkbox as CheckboxPrimitive } from '@base-ui-components/react/checkbox';
import { Icon } from '@backstage/canon';
import type { CheckboxProps } from './types';
import clsx from 'clsx';
/** @public */
export const Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(
export const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(
(props, ref) => {
const {
label,
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Box } from '../Box/Box';
import { Container } from './Container';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Flex } from './Flex';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Grid } from './Grid';
import type { GridItemProps } from './types';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Heading } from './Heading';
import { Flex } from '../Flex';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import clsx from 'clsx';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { Icon } from './Icon';
import { IconProvider } from './provider';
+2 -2
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import { ComponentType } from 'react';
import { useIcons } from './context';
import type { IconProps } from './types';
import clsx from 'clsx';
@@ -24,7 +24,7 @@ export const Icon = (props: IconProps) => {
const { name, size, className, style, ...restProps } = props;
const { icons } = useIcons();
const CanonIcon = icons[name] as React.ComponentType<Omit<IconProps, 'name'>>;
const CanonIcon = icons[name] as ComponentType<Omit<IconProps, 'name'>>;
if (!CanonIcon) {
console.error(`Icon "${name}" not found or is not a valid component.`);
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import { icons } from './icons';
import { IconContext } from './context';
import type { IconProviderProps } from './types';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { IconButton } from './IconButton';
import { Flex } from '../Flex';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import { Icon } from '../Icon';
import clsx from 'clsx';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Link } from './Link';
import { Flex } from '../Flex';
+2 -2
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { useRef, forwardRef } from 'react';
import { useRender } from '@base-ui-components/react/use-render';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
import clsx from 'clsx';
@@ -33,7 +33,7 @@ export const Link = forwardRef<HTMLElement, LinkProps>((props, ref) => {
const responsiveVariant = useResponsiveValue(variant);
const responsiveWeight = useResponsiveValue(weight);
const internalRef = React.useRef<HTMLElement | null>(null);
const internalRef = useRef<HTMLElement | null>(null);
const { renderElement } = useRender({
render,
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Menu } from './Menu';
import { Button } from '../Button';
+16 -16
View File
@@ -14,12 +14,12 @@
* limitations under the License.
*/
import React from 'react';
import { forwardRef } from 'react';
import { Menu as MenuPrimitive } from '@base-ui-components/react/menu';
import clsx from 'clsx';
import { MenuComponent } from './types';
const MenuTrigger = React.forwardRef<
const MenuTrigger = forwardRef<
React.ElementRef<typeof MenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Trigger>
>(({ className, ...props }, ref) => (
@@ -31,7 +31,7 @@ const MenuTrigger = React.forwardRef<
));
MenuTrigger.displayName = MenuPrimitive.Trigger.displayName;
const MenuBackdrop = React.forwardRef<
const MenuBackdrop = forwardRef<
React.ElementRef<typeof MenuPrimitive.Backdrop>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Backdrop>
>(({ className, ...props }, ref) => (
@@ -43,7 +43,7 @@ const MenuBackdrop = React.forwardRef<
));
MenuBackdrop.displayName = MenuPrimitive.Backdrop.displayName;
const MenuPositioner = React.forwardRef<
const MenuPositioner = forwardRef<
React.ElementRef<typeof MenuPrimitive.Positioner>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Positioner>
>(({ className, ...props }, ref) => (
@@ -55,7 +55,7 @@ const MenuPositioner = React.forwardRef<
));
MenuPositioner.displayName = MenuPrimitive.Positioner.displayName;
const MenuPopup = React.forwardRef<
const MenuPopup = forwardRef<
React.ElementRef<typeof MenuPrimitive.Popup>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Popup>
>(({ className, ...props }, ref) => (
@@ -67,7 +67,7 @@ const MenuPopup = React.forwardRef<
));
MenuPopup.displayName = MenuPrimitive.Popup.displayName;
const MenuArrow = React.forwardRef<
const MenuArrow = forwardRef<
React.ElementRef<typeof MenuPrimitive.Arrow>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Arrow>
>(({ className, ...props }, ref) => (
@@ -79,7 +79,7 @@ const MenuArrow = React.forwardRef<
));
MenuArrow.displayName = MenuPrimitive.Arrow.displayName;
const MenuItem = React.forwardRef<
const MenuItem = forwardRef<
React.ElementRef<typeof MenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Item>
>(({ className, ...props }, ref) => (
@@ -91,7 +91,7 @@ const MenuItem = React.forwardRef<
));
MenuItem.displayName = MenuPrimitive.Item.displayName;
const MenuGroup = React.forwardRef<
const MenuGroup = forwardRef<
React.ElementRef<typeof MenuPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Group>
>(({ className, ...props }, ref) => (
@@ -103,7 +103,7 @@ const MenuGroup = React.forwardRef<
));
MenuGroup.displayName = MenuPrimitive.Group.displayName;
const MenuGroupLabel = React.forwardRef<
const MenuGroupLabel = forwardRef<
React.ElementRef<typeof MenuPrimitive.GroupLabel>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.GroupLabel>
>(({ className, ...props }, ref) => (
@@ -115,7 +115,7 @@ const MenuGroupLabel = React.forwardRef<
));
MenuGroupLabel.displayName = MenuPrimitive.GroupLabel.displayName;
const MenuRadioGroup = React.forwardRef<
const MenuRadioGroup = forwardRef<
React.ElementRef<typeof MenuPrimitive.RadioGroup>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioGroup>
>(({ className, ...props }, ref) => (
@@ -127,7 +127,7 @@ const MenuRadioGroup = React.forwardRef<
));
MenuRadioGroup.displayName = MenuPrimitive.RadioGroup.displayName;
const MenuRadioItem = React.forwardRef<
const MenuRadioItem = forwardRef<
React.ElementRef<typeof MenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItem>
>(({ className, ...props }, ref) => (
@@ -139,7 +139,7 @@ const MenuRadioItem = React.forwardRef<
));
MenuRadioItem.displayName = MenuPrimitive.RadioItem.displayName;
const MenuRadioItemIndicator = React.forwardRef<
const MenuRadioItemIndicator = forwardRef<
React.ElementRef<typeof MenuPrimitive.RadioItemIndicator>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.RadioItemIndicator>
>(({ className, ...props }, ref) => (
@@ -152,7 +152,7 @@ const MenuRadioItemIndicator = React.forwardRef<
MenuRadioItemIndicator.displayName =
MenuPrimitive.RadioItemIndicator.displayName;
const MenuCheckboxItem = React.forwardRef<
const MenuCheckboxItem = forwardRef<
React.ElementRef<typeof MenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItem>
>(({ className, ...props }, ref) => (
@@ -164,7 +164,7 @@ const MenuCheckboxItem = React.forwardRef<
));
MenuCheckboxItem.displayName = MenuPrimitive.CheckboxItem.displayName;
const MenuCheckboxItemIndicator = React.forwardRef<
const MenuCheckboxItemIndicator = forwardRef<
React.ElementRef<typeof MenuPrimitive.CheckboxItemIndicator>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.CheckboxItemIndicator>
>(({ className, ...props }, ref) => (
@@ -177,7 +177,7 @@ const MenuCheckboxItemIndicator = React.forwardRef<
MenuCheckboxItemIndicator.displayName =
MenuPrimitive.CheckboxItemIndicator.displayName;
const MenuSubmenuTrigger = React.forwardRef<
const MenuSubmenuTrigger = forwardRef<
React.ElementRef<typeof MenuPrimitive.SubmenuTrigger>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.SubmenuTrigger>
>(({ className, ...props }, ref) => (
@@ -189,7 +189,7 @@ const MenuSubmenuTrigger = React.forwardRef<
));
MenuSubmenuTrigger.displayName = MenuPrimitive.SubmenuTrigger.displayName;
const MenuSeparator = React.forwardRef<
const MenuSeparator = forwardRef<
React.ElementRef<typeof MenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof MenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { ScrollArea } from './ScrollArea';
import { Text } from '../Text/Text';
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import React from 'react';
import { forwardRef } from 'react';
import { ScrollArea as ScrollAreaPrimitive } from '@base-ui-components/react/scroll-area';
import clsx from 'clsx';
const ScrollAreaRoot = React.forwardRef<
const ScrollAreaRoot = forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, ...props }, ref) => (
@@ -30,7 +30,7 @@ const ScrollAreaRoot = React.forwardRef<
));
ScrollAreaRoot.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollAreaViewport = React.forwardRef<
const ScrollAreaViewport = forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Viewport>
>(({ className, ...props }, ref) => (
@@ -42,7 +42,7 @@ const ScrollAreaViewport = React.forwardRef<
));
ScrollAreaViewport.displayName = ScrollAreaPrimitive.Viewport.displayName;
const ScrollAreaScrollbar = React.forwardRef<
const ScrollAreaScrollbar = forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Scrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Scrollbar>
>(({ className, ...props }, ref) => (
@@ -54,7 +54,7 @@ const ScrollAreaScrollbar = React.forwardRef<
));
ScrollAreaScrollbar.displayName = ScrollAreaPrimitive.Scrollbar.displayName;
const ScrollAreaThumb = React.forwardRef<
const ScrollAreaThumb = forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Thumb>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Thumb>
>(({ className, ...props }, ref) => (
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Select } from './Select';
import { Flex } from '../Flex';
+82 -84
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import { forwardRef, useId } from 'react';
import { Select as SelectPrimitive } from '@base-ui-components/react/select';
import { Icon } from '../Icon';
import clsx from 'clsx';
@@ -23,91 +23,89 @@ import { SelectProps } from './types';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
/** @public */
export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
(props, ref) => {
const {
className,
label,
description,
options,
placeholder = 'Select an option',
size = 'medium',
required,
error,
style,
...rest
} = props;
export const Select = forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
const {
className,
label,
description,
options,
placeholder = 'Select an option',
size = 'medium',
required,
error,
style,
...rest
} = props;
// Get the responsive value for the variant
const responsiveSize = useResponsiveValue(size);
// Get the responsive value for the variant
const responsiveSize = useResponsiveValue(size);
// Generate unique IDs for accessibility
const selectId = React.useId();
const descriptionId = React.useId();
const errorId = React.useId();
// Generate unique IDs for accessibility
const selectId = useId();
const descriptionId = useId();
const errorId = useId();
return (
<div className={clsx('canon-Select', className)} style={style} ref={ref}>
{label && (
<label className="canon-Select--label" htmlFor={selectId}>
{label}
{required && (
<span aria-hidden="true" className="canon-Select--required">
(Required)
</span>
)}
</label>
)}
<SelectPrimitive.Root {...rest}>
<SelectPrimitive.Trigger
id={selectId}
className={clsx('canon-Select--trigger', {
'canon-Select--trigger-size-small': responsiveSize === 'small',
'canon-Select--trigger-size-medium': responsiveSize === 'medium',
})}
data-invalid={error}
>
<SelectPrimitive.Value placeholder={placeholder} />
<SelectPrimitive.Icon className="canon-Select--icon">
<Icon name="chevron-down" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
<SelectPrimitive.Portal>
<SelectPrimitive.Backdrop />
<SelectPrimitive.Positioner>
<SelectPrimitive.Popup className="canon-Select--popup">
{options?.map(option => (
<SelectPrimitive.Item
key={option.value}
value={option.value}
disabled={option.disabled}
className="canon-Select--item"
>
<SelectPrimitive.ItemIndicator className="canon-Select--item-indicator">
<Icon name="check" />
</SelectPrimitive.ItemIndicator>
<SelectPrimitive.ItemText className="canon-Select--item-text">
{option.label}
</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))}
</SelectPrimitive.Popup>
</SelectPrimitive.Positioner>
</SelectPrimitive.Portal>
</SelectPrimitive.Root>
{description && (
<p className="canon-Select--description" id={descriptionId}>
{description}
</p>
)}
{error && (
<p className="canon-Select--error" id={errorId} role="alert">
{error}
</p>
)}
</div>
);
},
);
return (
<div className={clsx('canon-Select', className)} style={style} ref={ref}>
{label && (
<label className="canon-Select--label" htmlFor={selectId}>
{label}
{required && (
<span aria-hidden="true" className="canon-Select--required">
(Required)
</span>
)}
</label>
)}
<SelectPrimitive.Root {...rest}>
<SelectPrimitive.Trigger
id={selectId}
className={clsx('canon-Select--trigger', {
'canon-Select--trigger-size-small': responsiveSize === 'small',
'canon-Select--trigger-size-medium': responsiveSize === 'medium',
})}
data-invalid={error}
>
<SelectPrimitive.Value placeholder={placeholder} />
<SelectPrimitive.Icon className="canon-Select--icon">
<Icon name="chevron-down" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
<SelectPrimitive.Portal>
<SelectPrimitive.Backdrop />
<SelectPrimitive.Positioner>
<SelectPrimitive.Popup className="canon-Select--popup">
{options?.map(option => (
<SelectPrimitive.Item
key={option.value}
value={option.value}
disabled={option.disabled}
className="canon-Select--item"
>
<SelectPrimitive.ItemIndicator className="canon-Select--item-indicator">
<Icon name="check" />
</SelectPrimitive.ItemIndicator>
<SelectPrimitive.ItemText className="canon-Select--item-text">
{option.label}
</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))}
</SelectPrimitive.Popup>
</SelectPrimitive.Positioner>
</SelectPrimitive.Portal>
</SelectPrimitive.Root>
{description && (
<p className="canon-Select--description" id={descriptionId}>
{description}
</p>
)}
{error && (
<p className="canon-Select--error" id={errorId} role="alert">
{error}
</p>
)}
</div>
);
});
Select.displayName = 'Select';
@@ -59,7 +59,7 @@ const invoices = [
},
];
import React from 'react';
import { ComponentType } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import {
Table,
@@ -75,12 +75,12 @@ const meta = {
title: 'Components/Table',
component: Table,
subcomponents: {
TableBody: TableBody as React.ComponentType<unknown>,
TableCell: TableCell as React.ComponentType<unknown>,
TableFooter: TableFooter as React.ComponentType<unknown>,
TableHead: TableHead as React.ComponentType<unknown>,
TableHeader: TableHeader as React.ComponentType<unknown>,
TableRow: TableRow as React.ComponentType<unknown>,
TableBody: TableBody as ComponentType<unknown>,
TableCell: TableCell as ComponentType<unknown>,
TableFooter: TableFooter as ComponentType<unknown>,
TableHead: TableHead as ComponentType<unknown>,
TableHeader: TableHeader as ComponentType<unknown>,
TableRow: TableRow as ComponentType<unknown>,
},
} satisfies Meta<typeof Table>;
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as React from 'react';
import { forwardRef } from 'react';
/** @public */
const Table = React.forwardRef<
const Table = forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
@@ -27,7 +27,7 @@ const Table = React.forwardRef<
Table.displayName = 'Table';
/** @public */
const TableHeader = React.forwardRef<
const TableHeader = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
@@ -40,7 +40,7 @@ const TableHeader = React.forwardRef<
TableHeader.displayName = 'TableHeader';
/** @public */
const TableBody = React.forwardRef<
const TableBody = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
@@ -49,7 +49,7 @@ const TableBody = React.forwardRef<
TableBody.displayName = 'TableBody';
/** @public */
const TableFooter = React.forwardRef<
const TableFooter = forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
@@ -62,7 +62,7 @@ const TableFooter = React.forwardRef<
TableFooter.displayName = 'TableFooter';
/** @public */
const TableRow = React.forwardRef<
const TableRow = forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
@@ -73,7 +73,7 @@ const TableRow = React.forwardRef<
TableRow.displayName = 'TableRow';
/** @public */
const TableHead = React.forwardRef<
const TableHead = forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
@@ -82,7 +82,7 @@ const TableHead = React.forwardRef<
TableHead.displayName = 'TableHead';
/** @public */
const TableCell = React.forwardRef<
const TableCell = forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
@@ -91,7 +91,7 @@ const TableCell = React.forwardRef<
TableCell.displayName = 'TableCell';
/** @public */
const TableCaption = React.forwardRef<
const TableCaption = forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Text } from './Text';
import { Flex } from '../Flex';
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { forwardRef } from 'react';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
import clsx from 'clsx';
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { TextField } from './TextField';
import { Flex } from '../Flex';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { useId, forwardRef } from 'react';
import { Input } from '@base-ui-components/react/input';
import { useResponsiveValue } from '../../hooks/useResponsiveValue';
import clsx from 'clsx';
@@ -39,9 +39,9 @@ export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(
const responsiveSize = useResponsiveValue(size);
// Generate unique IDs for accessibility
const inputId = React.useId();
const descriptionId = React.useId();
const errorId = React.useId();
const inputId = useId();
const descriptionId = useId();
const errorId = useId();
return (
<div
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Tooltip } from './Tooltip';
import { Button } from '../Button/Button';
@@ -14,11 +14,11 @@
* limitations under the License.
*/
import React from 'react';
import { forwardRef } from 'react';
import { Tooltip as TooltipPrimitive } from '@base-ui-components/react/tooltip';
import clsx from 'clsx';
const TooltipTrigger = React.forwardRef<
const TooltipTrigger = forwardRef<
React.ElementRef<typeof TooltipPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>
>(({ className, ...props }, ref) => (
@@ -30,7 +30,7 @@ const TooltipTrigger = React.forwardRef<
));
TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName;
const TooltipPositioner = React.forwardRef<
const TooltipPositioner = forwardRef<
React.ElementRef<typeof TooltipPrimitive.Positioner>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Positioner>
>(({ className, ...props }, ref) => (
@@ -42,7 +42,7 @@ const TooltipPositioner = React.forwardRef<
));
TooltipPositioner.displayName = TooltipPrimitive.Positioner.displayName;
const TooltipPopup = React.forwardRef<
const TooltipPopup = forwardRef<
React.ElementRef<typeof TooltipPrimitive.Popup>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Popup>
>(({ className, ...props }, ref) => (
@@ -54,7 +54,7 @@ const TooltipPopup = React.forwardRef<
));
TooltipPopup.displayName = TooltipPrimitive.Popup.displayName;
const TooltipArrow = React.forwardRef<
const TooltipArrow = forwardRef<
React.ElementRef<typeof TooltipPrimitive.Arrow>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
>(({ className, ...props }, ref) => (
+4 -4
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { useForm, SubmitHandler, Controller } from 'react-hook-form';
import { TextField } from '../components/TextField';
@@ -105,9 +105,9 @@ export const Controlled: Story = {
formState: { errors },
} = useForm<Inputs>();
const [firstname, setFirstname] = React.useState('John');
const [lastname, setLastname] = React.useState('Doe');
const [city, setCity] = React.useState('london');
const [firstname, setFirstname] = useState('John');
const [lastname, setLastname] = useState('Doe');
const [city, setCity] = useState('london');
const onSubmit: SubmitHandler<Inputs> = data => {
console.log('data', data);
+19 -1
View File
@@ -243,8 +243,26 @@ function createConfigForRole(dir, role, extraConfig = {}) {
'@mui/*/*/*',
...(extraConfig.restrictedImportPatterns ?? []),
],
rules: {
'react/react-in-jsx-scope': 'off',
'no-restricted-syntax': [
'error',
{
message: 'Default React import not allowed.',
selector:
"ImportDeclaration[source.value='react'][specifiers.0.type='ImportDefaultSpecifier']",
},
{
message:
'Default React import not allowed. If you need a global type that collides with a React named export (such as `MouseEvent`), try using `globalThis.MouseHandler`.',
selector:
"ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
},
],
...extraConfig.rules,
},
tsRules: {
'react/prop-types': 0,
'react/prop-types': 'off',
...extraConfig.tsRules,
},
});
+1 -1
View File
@@ -11,7 +11,7 @@
"importHelpers": false,
"incremental": true,
"isolatedModules": true,
"jsx": "react",
"jsx": "react-jsx",
"lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2022"],
"module": "ESNext",
"moduleResolution": "node",
@@ -1,4 +1,3 @@
import React from 'react';
import { createDevApp } from '@backstage/dev-utils';
import { {{ pluginVar }}, {{ extensionName }} } from '../src/plugin';

Some files were not shown because too many files have changed in this diff Show More