extends Router {
@@ -925,10 +921,4 @@ type UnknownIfNever = [P] extends [never] ? unknown : P;
// @public
type ValueOf = T[keyof T];
-
-// @public
-export const wrapInOpenApiTestServer: (app: Express_2) => Server | Express_2;
-
-// @public
-export function wrapServer(app: Express_2): Promise;
```
diff --git a/packages/backend-openapi-utils/src/index.ts b/packages/backend-openapi-utils/src/index.ts
index 9389fe3be6..849cc72daf 100644
--- a/packages/backend-openapi-utils/src/index.ts
+++ b/packages/backend-openapi-utils/src/index.ts
@@ -32,7 +32,6 @@ export type {
} from './utility';
export type { ApiRouter, TypedRouter } from './router';
export type { PathTemplate } from './types/common';
-export { wrapInOpenApiTestServer, wrapServer } from './testUtils';
export {
createValidatedOpenApiRouter,
getOpenApiSpecRoute,
diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md
index 06c8531a4e..54f195ca71 100644
--- a/packages/backend-plugin-api/CHANGELOG.md
+++ b/packages/backend-plugin-api/CHANGELOG.md
@@ -1,5 +1,47 @@
# @backstage/backend-plugin-api
+## 1.2.0-next.0
+
+### Minor Changes
+
+- a4aa244: This change introduces the `auditor` service definition.
+
+### Patch Changes
+
+- 9ddfd94: Added new `PermissionsRegistryService` that is used by plugins to register permissions, resource types, and rules into the permission system. This replaces the existing `createPermissionIntegrationRouter` from `@backstage/plugin-permission-node`.
+- Updated dependencies
+ - @backstage/plugin-permission-node@0.8.8-next.0
+ - @backstage/cli-common@0.1.15
+ - @backstage/config@1.3.2
+ - @backstage/errors@1.2.7
+ - @backstage/types@1.2.1
+ - @backstage/plugin-auth-node@0.5.7-next.0
+ - @backstage/plugin-permission-common@0.8.4
+
+## 1.1.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/types@1.2.1
+ - @backstage/plugin-auth-node@0.5.6
+ - @backstage/cli-common@0.1.15
+ - @backstage/config@1.3.2
+ - @backstage/errors@1.2.7
+ - @backstage/plugin-permission-common@0.8.4
+
+## 1.1.1-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/types@1.2.1-next.0
+ - @backstage/config@1.3.2-next.0
+ - @backstage/errors@1.2.7-next.0
+ - @backstage/plugin-auth-node@0.5.6-next.1
+ - @backstage/plugin-permission-common@0.8.4-next.0
+ - @backstage/cli-common@0.1.15
+
## 1.1.1-next.0
### Patch Changes
diff --git a/packages/backend-plugin-api/knip-report.md b/packages/backend-plugin-api/knip-report.md
index 2661c35327..89988530e6 100644
--- a/packages/backend-plugin-api/knip-report.md
+++ b/packages/backend-plugin-api/knip-report.md
@@ -1,2 +1,8 @@
# Knip report
+## Unused dependencies (1)
+
+| Name | Location | Severity |
+| :-------------------------- | :----------- | :------- |
+| @backstage/plugin-auth-node | package.json | error |
+
diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json
index c8577fbea8..9c78a6cd15 100644
--- a/packages/backend-plugin-api/package.json
+++ b/packages/backend-plugin-api/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/backend-plugin-api",
- "version": "1.1.1-next.0",
+ "version": "1.2.0-next.0",
"description": "Core API used by Backstage backend plugins",
"backstage": {
"role": "node-library"
@@ -58,6 +58,7 @@
"@backstage/errors": "workspace:^",
"@backstage/plugin-auth-node": "workspace:^",
"@backstage/plugin-permission-common": "workspace:^",
+ "@backstage/plugin-permission-node": "workspace:^",
"@backstage/types": "workspace:^",
"@types/express": "^4.17.6",
"@types/luxon": "^3.0.0",
diff --git a/packages/backend-plugin-api/report.api.md b/packages/backend-plugin-api/report.api.md
index 8416c6c200..a4f9b9fa1d 100644
--- a/packages/backend-plugin-api/report.api.md
+++ b/packages/backend-plugin-api/report.api.md
@@ -16,14 +16,45 @@ import { isChildPath } from '@backstage/cli-common';
import { JsonObject } from '@backstage/types';
import { JsonValue } from '@backstage/types';
import { Knex } from 'knex';
+import { Permission } from '@backstage/plugin-permission-common';
import { PermissionAttributes } from '@backstage/plugin-permission-common';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
+import { PermissionRule } from '@backstage/plugin-permission-node';
import { QueryPermissionRequest } from '@backstage/plugin-permission-common';
import { QueryPermissionResponse } from '@backstage/plugin-permission-common';
import { Readable } from 'stream';
import type { Request as Request_2 } from 'express';
import type { Response as Response_2 } from 'express';
+// @public
+export interface AuditorService {
+ // (undocumented)
+ createEvent(
+ options: AuditorServiceCreateEventOptions,
+ ): Promise;
+}
+
+// @public (undocumented)
+export type AuditorServiceCreateEventOptions = {
+ eventId: string;
+ severityLevel?: AuditorServiceEventSeverityLevel;
+ request?: Request_2;
+ meta?: JsonObject;
+};
+
+// @public (undocumented)
+export type AuditorServiceEvent = {
+ success(options?: { meta?: JsonObject }): Promise;
+ fail(options: { meta?: JsonObject; error: Error }): Promise;
+};
+
+// @public
+export type AuditorServiceEventSeverityLevel =
+ | 'low'
+ | 'medium'
+ | 'high'
+ | 'critical';
+
// @public
export interface AuthService {
authenticate(
@@ -183,7 +214,13 @@ export namespace coreServices {
const httpRouter: ServiceRef;
const lifecycle: ServiceRef;
const logger: ServiceRef;
+ const auditor: ServiceRef;
const permissions: ServiceRef;
+ const permissionsRegistry: ServiceRef<
+ PermissionsRegistryService,
+ 'plugin',
+ 'singleton'
+ >;
const pluginMetadata: ServiceRef<
PluginMetadataService,
'plugin',
@@ -425,6 +462,29 @@ export interface LoggerService {
warn(message: string, meta?: Error | JsonObject): void;
}
+// @public
+export interface PermissionsRegistryService {
+ addPermissionRules(rules: PermissionRule[]): void;
+ addPermissions(permissions: Permission[]): void;
+ addResourceType(
+ options: PermissionsRegistryServiceAddResourceTypeOptions<
+ TResourceType,
+ TResource
+ >,
+ ): void;
+}
+
+// @public
+export type PermissionsRegistryServiceAddResourceTypeOptions<
+ TResourceType extends string,
+ TResource,
+> = {
+ resourceType: TResourceType;
+ permissions?: Array;
+ rules: PermissionRule>[];
+ getResources?(resourceRefs: string[]): Promise>;
+};
+
// @public
export interface PermissionsService extends PermissionEvaluator {
authorize(
diff --git a/packages/backend-plugin-api/src/services/definitions/AuditorService.ts b/packages/backend-plugin-api/src/services/definitions/AuditorService.ts
new file mode 100644
index 0000000000..c98fe65df3
--- /dev/null
+++ b/packages/backend-plugin-api/src/services/definitions/AuditorService.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2024 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 type { JsonObject } from '@backstage/types';
+import type { Request } from 'express';
+
+/**
+ * low (default): normal usage
+ * medium: accessing write endpoints
+ * high: non-root permission changes
+ * critical: root permission changes
+ * @public
+ */
+export type AuditorServiceEventSeverityLevel =
+ | 'low'
+ | 'medium'
+ | 'high'
+ | 'critical';
+
+/** @public */
+export type AuditorServiceCreateEventOptions = {
+ /**
+ * Use kebab-case to name audit events (e.g., "user-login", "file-download", "fetch"). Represents a logical group of similar events or operations. For example, "fetch" could be used as an eventId encompassing various fetch methods like "by-id" or "by-location".
+ *
+ * The `pluginId` already provides plugin/module context, so avoid redundant prefixes in the `eventId`.
+ */
+ eventId: string;
+
+ /** (Optional) The severity level for the audit event. */
+ severityLevel?: AuditorServiceEventSeverityLevel;
+
+ /** (Optional) The associated HTTP request, if applicable. */
+ request?: Request;
+
+ /**
+ * (Optional) Additional metadata relevant to the event, structured as a JSON object.
+ * This could include a `queryType` field, using kebab-case, for variations within the main event (e.g., "by-id", "by-user").
+ * For example, if the `eventId` is "fetch", the `queryType` in `meta` could be "by-id" or "by-location".
+ */
+ meta?: JsonObject;
+};
+
+/** @public */
+export type AuditorServiceEvent = {
+ success(options?: { meta?: JsonObject }): Promise;
+ fail(options: { meta?: JsonObject; error: Error }): Promise;
+};
+
+/**
+ * A service that provides an auditor facility.
+ *
+ * See the {@link https://backstage.io/docs/backend-system/core-services/auditor | service documentation} for more details.
+ *
+ * @public
+ */
+export interface AuditorService {
+ createEvent(
+ options: AuditorServiceCreateEventOptions,
+ ): Promise;
+}
diff --git a/packages/backend-plugin-api/src/services/definitions/PermissionsRegistryService.ts b/packages/backend-plugin-api/src/services/definitions/PermissionsRegistryService.ts
new file mode 100644
index 0000000000..46236aa6cc
--- /dev/null
+++ b/packages/backend-plugin-api/src/services/definitions/PermissionsRegistryService.ts
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2022 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 { Permission } from '@backstage/plugin-permission-common';
+import { PermissionRule } from '@backstage/plugin-permission-node';
+
+/**
+ * Prevent use of type parameter from contributing to type inference.
+ *
+ * https://github.com/Microsoft/TypeScript/issues/14829#issuecomment-980401795
+ * @ignore
+ */
+type NoInfer = T extends infer S ? S : never;
+
+/**
+ * Options for adding a resource type to the permission system.
+ *
+ * @public
+ */
+export type PermissionsRegistryServiceAddResourceTypeOptions<
+ TResourceType extends string,
+ TResource,
+> = {
+ /**
+ * The identifier for the resource type.
+ */
+ resourceType: TResourceType;
+
+ /**
+ * Permissions that are available for this resource type.
+ */
+ permissions?: Array;
+
+ /**
+ * Permission rules that are available for this resource type.
+ */
+ rules: PermissionRule>[];
+
+ /**
+ * The function used to load associated resources based in the provided
+ * references.
+ *
+ * @remarks
+ *
+ * If this function is not provided the permission system will not be able to
+ * resolve conditional decisions except when requesting resources directly
+ * from the plugin.
+ */
+ getResources?(resourceRefs: string[]): Promise>;
+};
+
+/**
+ * Permission system integration for registering resources and permissions.
+ *
+ * See the {@link https://backstage.io/docs/permissions/overview | permissions documentation}
+ * and the {@link https://backstage.io/docs/backend-system/core-services/permission-integrations | service documentation}
+ * for more details.
+ *
+ * @public
+ */
+export interface PermissionsRegistryService {
+ /**
+ * Add permissions for this plugin to the permission system.
+ */
+ addPermissions(permissions: Permission[]): void;
+
+ /**
+ * Adds a set of permission rules to the permission system for a resource type
+ * that is owned by this plugin.
+ *
+ * @remarks
+ *
+ * Rules should be created using corresponding `create*PermissionRule`
+ * functions exported by plugins, who in turn are created with
+ * `makeCreatePermissionRule`.
+ *
+ * Rules can be added either directly by the plugin itself or through a plugin
+ * module.
+ */
+ addPermissionRules(rules: PermissionRule[]): void;
+
+ /**
+ * Add a new resource type that is owned by this plugin to the permission
+ * system.
+ *
+ * @remarks
+ *
+ * To make this concrete, we can use the Backstage software catalog as an
+ * example. The catalog has conditional rules around access to specific
+ * _entities_ in the catalog. The _type_ of resource is captured here as
+ * `resourceType`, a string identifier (`catalog-entity` in this example) that
+ * can be provided with permission definitions. This is merely a _type_ to
+ * verify that conditions in an authorization policy are constructed
+ * correctly, not a reference to a specific resource.
+ *
+ * The `rules` parameter is an array of
+ * {@link @backstage/plugin-permission-node#PermissionRule}s that introduce
+ * conditional filtering logic for resources; for the catalog, these are
+ * things like `isEntityOwner` or `hasAnnotation`. Rules describe how to
+ * filter a list of resources, and the `conditions` returned allow these rules
+ * to be applied with specific parameters (such as 'group:default/team-a', or
+ * 'backstage.io/edit-url').
+ *
+ * The `getResources` argument should load resources based on a reference
+ * identifier. For the catalog, this is an
+ * [entity reference](https://backstage.io/docs/features/software-catalog/references#string-references).
+ * For other plugins, this can be any serialized format. This is used to add a
+ * permissions registry API via the HTTP router service. This API will be
+ * called by the `permission-backend` when authorization conditions relating
+ * to this plugin need to be evaluated.
+ */
+ addResourceType(
+ options: PermissionsRegistryServiceAddResourceTypeOptions<
+ TResourceType,
+ TResource
+ >,
+ ): void;
+}
diff --git a/packages/backend-plugin-api/src/services/definitions/coreServices.ts b/packages/backend-plugin-api/src/services/definitions/coreServices.ts
index f87bff023c..8c8c6c0f82 100644
--- a/packages/backend-plugin-api/src/services/definitions/coreServices.ts
+++ b/packages/backend-plugin-api/src/services/definitions/coreServices.ts
@@ -161,6 +161,19 @@ export namespace coreServices {
import('./LoggerService').LoggerService
>({ id: 'core.logger' });
+ /**
+ * Plugin-level auditing.
+ *
+ * See {@link AuditorService}
+ * and {@link https://backstage.io/docs/backend-system/core-services/auditor | the service docs}
+ * for more information.
+ *
+ * @public
+ */
+ export const auditor = createServiceRef<
+ import('./AuditorService').AuditorService
+ >({ id: 'core.auditor' });
+
/**
* Permission system integration for authorization of user actions.
*
@@ -174,6 +187,19 @@ export namespace coreServices {
import('./PermissionsService').PermissionsService
>({ id: 'core.permissions' });
+ /**
+ * Permission system integration for registering resources and permissions.
+ *
+ * See {@link PermissionsRegistryService}
+ * and {@link https://backstage.io/docs/backend-system/core-services/permission-integrations | the service docs}
+ * for more information.
+ *
+ * @public
+ */
+ export const permissionsRegistry = createServiceRef<
+ import('./PermissionsRegistryService').PermissionsRegistryService
+ >({ id: 'core.permissionsRegistry' });
+
/**
* Built-in service for accessing metadata about the current plugin.
*
diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts
index 1df00bdead..d6346cbe4e 100644
--- a/packages/backend-plugin-api/src/services/definitions/index.ts
+++ b/packages/backend-plugin-api/src/services/definitions/index.ts
@@ -14,43 +14,52 @@
* limitations under the License.
*/
-export { coreServices } from './coreServices';
+export type {
+ AuditorService,
+ AuditorServiceCreateEventOptions,
+ AuditorServiceEvent,
+ AuditorServiceEventSeverityLevel,
+} from './AuditorService';
export type {
AuthService,
BackstageCredentials,
- BackstageUserPrincipal,
- BackstageServicePrincipal,
+ BackstageNonePrincipal,
BackstagePrincipalAccessRestrictions,
BackstagePrincipalTypes,
- BackstageNonePrincipal,
+ BackstageServicePrincipal,
+ BackstageUserPrincipal,
} from './AuthService';
export type {
CacheService,
CacheServiceOptions,
CacheServiceSetOptions,
} from './CacheService';
-export type { RootConfigService } from './RootConfigService';
export type { DatabaseService } from './DatabaseService';
export type { DiscoveryService } from './DiscoveryService';
-export type { RootHealthService } from './RootHealthService';
+export type { HttpAuthService } from './HttpAuthService';
export type {
HttpRouterService,
HttpRouterServiceAuthPolicy,
} from './HttpRouterService';
-export type { HttpAuthService } from './HttpAuthService';
export type {
LifecycleService,
- LifecycleServiceStartupHook,
- LifecycleServiceStartupOptions,
LifecycleServiceShutdownHook,
LifecycleServiceShutdownOptions,
+ LifecycleServiceStartupHook,
+ LifecycleServiceStartupOptions,
} from './LifecycleService';
export type { LoggerService } from './LoggerService';
export type {
PermissionsService,
PermissionsServiceRequestOptions,
} from './PermissionsService';
+export type {
+ PermissionsRegistryService,
+ PermissionsRegistryServiceAddResourceTypeOptions,
+} from './PermissionsRegistryService';
export type { PluginMetadataService } from './PluginMetadataService';
+export type { RootConfigService } from './RootConfigService';
+export type { RootHealthService } from './RootHealthService';
export type { RootHttpRouterService } from './RootHttpRouterService';
export type { RootLifecycleService } from './RootLifecycleService';
export type { RootLoggerService } from './RootLoggerService';
@@ -65,15 +74,16 @@ export type {
SchedulerServiceTaskScheduleDefinitionConfig,
} from './SchedulerService';
export type {
+ UrlReaderService,
UrlReaderServiceReadTreeOptions,
UrlReaderServiceReadTreeResponse,
UrlReaderServiceReadTreeResponseDirOptions,
UrlReaderServiceReadTreeResponseFile,
- UrlReaderServiceReadUrlResponse,
UrlReaderServiceReadUrlOptions,
+ UrlReaderServiceReadUrlResponse,
UrlReaderServiceSearchOptions,
UrlReaderServiceSearchResponse,
UrlReaderServiceSearchResponseFile,
- UrlReaderService,
} from './UrlReaderService';
export type { BackstageUserInfo, UserInfoService } from './UserInfoService';
+export { coreServices } from './coreServices';
diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md
index da9418451f..ec4023c02b 100644
--- a/packages/backend-test-utils/CHANGELOG.md
+++ b/packages/backend-test-utils/CHANGELOG.md
@@ -1,5 +1,68 @@
# @backstage/backend-test-utils
+## 1.3.0-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/backend-app-api@1.1.2-next.1
+ - @backstage/backend-defaults@0.8.0-next.1
+ - @backstage/backend-plugin-api@1.2.0-next.0
+ - @backstage/config@1.3.2
+ - @backstage/errors@1.2.7
+ - @backstage/types@1.2.1
+ - @backstage/plugin-auth-node@0.5.7-next.0
+ - @backstage/plugin-events-node@0.4.8-next.0
+
+## 1.3.0-next.0
+
+### Minor Changes
+
+- dd05a97: Added mocks for the new `PermissionsRegistryService`.
+- a4aa244: This change introduces mocks for the `auditor` service.
+
+### Patch Changes
+
+- f866b86: Internal refactor to use explicit `require` for lazy-loading dependency.
+- fb051f2: Sync feature installation compatibility logic with `@backstage/backend-app-api`.
+- Updated dependencies
+ - @backstage/backend-defaults@0.8.0-next.0
+ - @backstage/backend-plugin-api@1.2.0-next.0
+ - @backstage/backend-app-api@1.1.2-next.0
+ - @backstage/config@1.3.2
+ - @backstage/errors@1.2.7
+ - @backstage/types@1.2.1
+ - @backstage/plugin-auth-node@0.5.7-next.0
+ - @backstage/plugin-events-node@0.4.8-next.0
+
+## 1.2.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/backend-defaults@0.7.0
+ - @backstage/backend-app-api@1.1.1
+ - @backstage/types@1.2.1
+ - @backstage/plugin-auth-node@0.5.6
+ - @backstage/backend-plugin-api@1.1.1
+ - @backstage/config@1.3.2
+ - @backstage/errors@1.2.7
+ - @backstage/plugin-events-node@0.4.7
+
+## 1.2.1-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/types@1.2.1-next.0
+ - @backstage/backend-app-api@1.1.1-next.1
+ - @backstage/backend-defaults@0.7.0-next.1
+ - @backstage/backend-plugin-api@1.1.1-next.1
+ - @backstage/config@1.3.2-next.0
+ - @backstage/errors@1.2.7-next.0
+ - @backstage/plugin-auth-node@0.5.6-next.1
+ - @backstage/plugin-events-node@0.4.7-next.1
+
## 1.2.1-next.0
### Patch Changes
diff --git a/packages/backend-test-utils/knip-report.md b/packages/backend-test-utils/knip-report.md
index 18741dce81..6ba3e32cd6 100644
--- a/packages/backend-test-utils/knip-report.md
+++ b/packages/backend-test-utils/knip-report.md
@@ -1,11 +1,13 @@
# Knip report
-## Unused dependencies (4)
+## Unused dependencies (6)
-| Name | Location | Severity |
-| :------------- | :----------- | :------- |
-| better-sqlite3 | package.json | error |
-| mysql2 | package.json | error |
-| msw | package.json | error |
-| pg | package.json | error |
+| Name | Location | Severity |
+| :------------------------------- | :----------- | :------- |
+| @types/express-serve-static-core | package.json | error |
+| @backstage/plugin-auth-node | package.json | error |
+| better-sqlite3 | package.json | error |
+| @types/qs | package.json | error |
+| mysql2 | package.json | error |
+| pg | package.json | error |
diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json
index c70a36e1f4..25ce2aa95f 100644
--- a/packages/backend-test-utils/package.json
+++ b/packages/backend-test-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/backend-test-utils",
- "version": "1.2.1-next.0",
+ "version": "1.3.0-next.1",
"description": "Test helpers library for Backstage backends",
"backstage": {
"role": "node-library"
diff --git a/packages/backend-test-utils/report.api.md b/packages/backend-test-utils/report.api.md
index a79bd9d03c..b358b268dc 100644
--- a/packages/backend-test-utils/report.api.md
+++ b/packages/backend-test-utils/report.api.md
@@ -8,6 +8,7 @@
///
///
+import { AuditorService } from '@backstage/backend-plugin-api';
import { AuthService } from '@backstage/backend-plugin-api';
import { Backend } from '@backstage/backend-app-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
@@ -33,6 +34,7 @@ import { LifecycleService } from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { ParamsDictionary } from 'express-serve-static-core';
import { ParsedQs } from 'qs';
+import { PermissionsRegistryService } from '@backstage/backend-plugin-api';
import { PermissionsService } from '@backstage/backend-plugin-api';
import { RootConfigService } from '@backstage/backend-plugin-api';
import { RootHealthService } from '@backstage/backend-plugin-api';
@@ -152,6 +154,15 @@ export function mockErrorHandler(): ErrorRequestHandler<
// @public
export namespace mockServices {
+ // (undocumented)
+ export namespace auditor {
+ const // (undocumented)
+ factory: () => ServiceFactory;
+ const // (undocumented)
+ mock: (
+ partialImpl?: Partial | undefined,
+ ) => ServiceMock;
+ }
// (undocumented)
export function auth(options?: {
pluginId?: string;
@@ -264,6 +275,19 @@ export namespace mockServices {
) => ServiceMock;
}
// (undocumented)
+ export namespace permissionsRegistry {
+ const // (undocumented)
+ factory: () => ServiceFactory<
+ PermissionsRegistryService,
+ 'plugin',
+ 'singleton'
+ >;
+ const // (undocumented)
+ mock: (
+ partialImpl?: Partial | undefined,
+ ) => ServiceMock;
+ }
+ // (undocumented)
export function rootConfig(options?: rootConfig.Options): RootConfigService;
// (undocumented)
export namespace rootConfig {
diff --git a/packages/backend-test-utils/src/cache/memcache.ts b/packages/backend-test-utils/src/cache/memcache.ts
index b7ac07cb13..e985ee1c7d 100644
--- a/packages/backend-test-utils/src/cache/memcache.ts
+++ b/packages/backend-test-utils/src/cache/memcache.ts
@@ -59,7 +59,8 @@ export async function startMemcachedContainer(
image: string,
): Promise {
// Lazy-load to avoid side-effect of importing testcontainers
- const { GenericContainer } = await import('testcontainers');
+ const { GenericContainer } =
+ require('testcontainers') as typeof import('testcontainers');
const container = await new GenericContainer(image)
.withExposedPorts(11211)
diff --git a/packages/backend-test-utils/src/cache/redis.ts b/packages/backend-test-utils/src/cache/redis.ts
index 6185e4d076..cd6e5c2893 100644
--- a/packages/backend-test-utils/src/cache/redis.ts
+++ b/packages/backend-test-utils/src/cache/redis.ts
@@ -57,7 +57,8 @@ export async function connectToExternalRedis(
export async function startRedisContainer(image: string): Promise {
// Lazy-load to avoid side-effect of importing testcontainers
- const { GenericContainer } = await import('testcontainers');
+ const { GenericContainer } =
+ require('testcontainers') as typeof import('testcontainers');
const container = await new GenericContainer(image)
.withExposedPorts(6379)
diff --git a/packages/backend-test-utils/src/database/mysql.ts b/packages/backend-test-utils/src/database/mysql.ts
index b27edb7f9d..a7c11d8452 100644
--- a/packages/backend-test-utils/src/database/mysql.ts
+++ b/packages/backend-test-utils/src/database/mysql.ts
@@ -72,7 +72,8 @@ export async function startMysqlContainer(image: string): Promise<{
const password = uuid();
// Lazy-load to avoid side-effect of importing testcontainers
- const { GenericContainer } = await import('testcontainers');
+ const { GenericContainer } =
+ require('testcontainers') as typeof import('testcontainers');
const container = await new GenericContainer(image)
.withExposedPorts(3306)
diff --git a/packages/backend-test-utils/src/database/postgres.ts b/packages/backend-test-utils/src/database/postgres.ts
index c8a946d121..e6122b9ab7 100644
--- a/packages/backend-test-utils/src/database/postgres.ts
+++ b/packages/backend-test-utils/src/database/postgres.ts
@@ -72,7 +72,8 @@ export async function startPostgresContainer(image: string): Promise<{
const password = uuid();
// Lazy-load to avoid side-effect of importing testcontainers
- const { GenericContainer } = await import('testcontainers');
+ const { GenericContainer } =
+ require('testcontainers') as typeof import('testcontainers');
const container = await new GenericContainer(image)
.withExposedPorts(5432)
diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts
index b9bca62767..15026d5dda 100644
--- a/packages/backend-test-utils/src/next/services/mockServices.ts
+++ b/packages/backend-test-utils/src/next/services/mockServices.ts
@@ -21,6 +21,7 @@ import { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter
import { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle';
import { loggerServiceFactory } from '@backstage/backend-defaults/logger';
import { permissionsServiceFactory } from '@backstage/backend-defaults/permissions';
+import { permissionsRegistryServiceFactory } from '@backstage/backend-defaults/permissionsRegistry';
import { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth';
import { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter';
import { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle';
@@ -47,12 +48,13 @@ import {
eventsServiceRef,
} from '@backstage/plugin-events-node';
import { JsonObject } from '@backstage/types';
+import { Knex } from 'knex';
import { MockAuthService } from './MockAuthService';
import { MockHttpAuthService } from './MockHttpAuthService';
import { MockRootLoggerService } from './MockRootLoggerService';
import { MockUserInfoService } from './MockUserInfoService';
import { mockCredentials } from './mockCredentials';
-import { Knex } from 'knex';
+import { auditorServiceFactory } from '@backstage/backend-defaults/auditor';
/** @internal */
function createLoggerMock() {
@@ -220,6 +222,19 @@ export namespace mockServices {
}));
}
+ export namespace auditor {
+ export const factory = () => auditorServiceFactory;
+
+ export const mock = simpleMock(coreServices.auditor, () => ({
+ createEvent: jest.fn(async _ => {
+ return {
+ success: jest.fn(),
+ fail: jest.fn(),
+ };
+ }),
+ }));
+ }
+
export function auth(options?: {
pluginId?: string;
disableDefaultAuthPolicy?: boolean;
@@ -468,6 +483,15 @@ export namespace mockServices {
}));
}
+ export namespace permissionsRegistry {
+ export const factory = () => permissionsRegistryServiceFactory;
+ export const mock = simpleMock(coreServices.permissionsRegistry, () => ({
+ addPermissionRules: jest.fn(),
+ addPermissions: jest.fn(),
+ addResourceType: jest.fn(),
+ }));
+ }
+
export namespace rootLifecycle {
export const factory = () => rootLifecycleServiceFactory;
export const mock = simpleMock(coreServices.rootLifecycle, () => ({
diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
index 4471f6ed24..20d02cf880 100644
--- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts
+++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts
@@ -67,6 +67,7 @@ export interface TestBackend extends Backend {
export const defaultServiceFactories = [
mockServices.auth.factory(),
+ mockServices.auditor.factory(),
mockServices.cache.factory(),
mockServices.rootConfig.factory(),
mockServices.database.factory(),
@@ -75,6 +76,7 @@ export const defaultServiceFactories = [
mockServices.lifecycle.factory(),
mockServices.logger.factory(),
mockServices.permissions.factory(),
+ mockServices.permissionsRegistry.factory(),
mockServices.rootHealth.factory(),
mockServices.rootLifecycle.factory(),
mockServices.rootLogger.factory(),
@@ -209,10 +211,19 @@ function isPromise(value: unknown | Promise): value is Promise {
);
}
+// Same as in the backend-app-api, handles double defaults from dynamic imports
function unwrapFeature(
- feature: BackendFeature | (() => BackendFeature),
+ feature: BackendFeature | { default: BackendFeature },
): BackendFeature {
- return typeof feature === 'function' ? feature() : feature;
+ if ('$$type' in feature) {
+ return feature;
+ }
+
+ if ('default' in feature) {
+ return feature.default;
+ }
+
+ return feature;
}
const backendInstancesToCleanUp = new Array();
diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md
index 2fcbe827eb..24b117b316 100644
--- a/packages/backend/CHANGELOG.md
+++ b/packages/backend/CHANGELOG.md
@@ -1,5 +1,157 @@
# example-backend
+## 0.0.35-next.1
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend@1.30.0-next.1
+ - @backstage/plugin-catalog-backend@1.31.0-next.1
+ - @backstage/backend-defaults@0.8.0-next.1
+ - @backstage/plugin-app-backend@0.4.5-next.0
+ - @backstage/plugin-events-backend@0.4.2-next.1
+ - @backstage/plugin-kubernetes-backend@0.19.3-next.1
+ - @backstage/plugin-proxy-backend@0.5.11-next.0
+ - @backstage/backend-plugin-api@1.2.0-next.0
+ - @backstage/catalog-model@1.7.3
+ - @backstage/plugin-auth-backend@0.24.3-next.1
+ - @backstage/plugin-auth-backend-module-github-provider@0.2.5-next.0
+ - @backstage/plugin-auth-backend-module-guest-provider@0.2.5-next.0
+ - @backstage/plugin-auth-node@0.5.7-next.0
+ - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.5-next.1
+ - @backstage/plugin-catalog-backend-module-openapi@0.2.7-next.1
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.5-next.1
+ - @backstage/plugin-catalog-backend-module-unprocessed@0.5.5-next.1
+ - @backstage/plugin-devtools-backend@0.5.2-next.1
+ - @backstage/plugin-notifications-backend@0.5.2-next.1
+ - @backstage/plugin-permission-backend@0.5.54-next.0
+ - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.5-next.0
+ - @backstage/plugin-permission-common@0.8.4
+ - @backstage/plugin-permission-node@0.8.8-next.0
+ - @backstage/plugin-scaffolder-backend-module-github@0.5.6-next.0
+ - @backstage/plugin-scaffolder-backend-module-notifications@0.1.7-next.0
+ - @backstage/plugin-search-backend@1.8.2-next.1
+ - @backstage/plugin-search-backend-module-catalog@0.3.1-next.1
+ - @backstage/plugin-search-backend-module-explore@0.2.8-next.0
+ - @backstage/plugin-search-backend-module-techdocs@0.3.6-next.1
+ - @backstage/plugin-search-backend-node@1.3.8-next.0
+ - @backstage/plugin-signals-backend@0.3.1-next.0
+ - @backstage/plugin-techdocs-backend@1.11.6-next.1
+
+## 0.0.35-next.0
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-permission-node@0.8.8-next.0
+ - @backstage/plugin-notifications-backend@0.5.2-next.0
+ - @backstage/backend-defaults@0.8.0-next.0
+ - @backstage/plugin-catalog-backend@1.31.0-next.0
+ - @backstage/plugin-kubernetes-backend@0.19.3-next.0
+ - @backstage/plugin-catalog-backend-module-unprocessed@0.5.5-next.0
+ - @backstage/backend-plugin-api@1.2.0-next.0
+ - @backstage/plugin-scaffolder-backend@1.30.0-next.0
+ - @backstage/plugin-catalog-backend-module-openapi@0.2.7-next.0
+ - @backstage/plugin-search-backend-module-catalog@0.3.1-next.0
+ - @backstage/plugin-devtools-backend@0.5.2-next.0
+ - @backstage/plugin-permission-backend@0.5.54-next.0
+ - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.5-next.0
+ - @backstage/plugin-search-backend@1.8.2-next.0
+ - @backstage/catalog-model@1.7.3
+ - @backstage/plugin-app-backend@0.4.5-next.0
+ - @backstage/plugin-auth-backend@0.24.3-next.0
+ - @backstage/plugin-auth-backend-module-github-provider@0.2.5-next.0
+ - @backstage/plugin-auth-backend-module-guest-provider@0.2.5-next.0
+ - @backstage/plugin-auth-node@0.5.7-next.0
+ - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.5-next.0
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.5-next.0
+ - @backstage/plugin-events-backend@0.4.2-next.0
+ - @backstage/plugin-permission-common@0.8.4
+ - @backstage/plugin-proxy-backend@0.5.11-next.0
+ - @backstage/plugin-scaffolder-backend-module-github@0.5.6-next.0
+ - @backstage/plugin-scaffolder-backend-module-notifications@0.1.7-next.0
+ - @backstage/plugin-search-backend-module-explore@0.2.8-next.0
+ - @backstage/plugin-search-backend-module-techdocs@0.3.6-next.0
+ - @backstage/plugin-search-backend-node@1.3.8-next.0
+ - @backstage/plugin-signals-backend@0.3.1-next.0
+ - @backstage/plugin-techdocs-backend@1.11.6-next.0
+
+## 0.0.34
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/plugin-scaffolder-backend-module-github@0.5.5
+ - @backstage/plugin-catalog-backend-module-openapi@0.2.6
+ - @backstage/plugin-devtools-backend@0.5.1
+ - @backstage/plugin-signals-backend@0.3.0
+ - @backstage/backend-defaults@0.7.0
+ - @backstage/plugin-scaffolder-backend@1.29.0
+ - @backstage/plugin-proxy-backend@0.5.10
+ - @backstage/plugin-search-backend-module-catalog@0.3.0
+ - @backstage/plugin-techdocs-backend@1.11.5
+ - @backstage/plugin-permission-backend@0.5.53
+ - @backstage/plugin-catalog-backend@1.30.0
+ - @backstage/plugin-permission-node@0.8.7
+ - @backstage/plugin-events-backend@0.4.1
+ - @backstage/plugin-app-backend@0.4.4
+ - @backstage/plugin-auth-node@0.5.6
+ - @backstage/plugin-notifications-backend@0.5.1
+ - @backstage/plugin-auth-backend@0.24.2
+ - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.4
+ - @backstage/backend-plugin-api@1.1.1
+ - @backstage/catalog-model@1.7.3
+ - @backstage/plugin-auth-backend-module-github-provider@0.2.4
+ - @backstage/plugin-auth-backend-module-guest-provider@0.2.4
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.4
+ - @backstage/plugin-catalog-backend-module-unprocessed@0.5.4
+ - @backstage/plugin-kubernetes-backend@0.19.2
+ - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.4
+ - @backstage/plugin-permission-common@0.8.4
+ - @backstage/plugin-scaffolder-backend-module-notifications@0.1.6
+ - @backstage/plugin-search-backend@1.8.1
+ - @backstage/plugin-search-backend-module-explore@0.2.7
+ - @backstage/plugin-search-backend-module-techdocs@0.3.5
+ - @backstage/plugin-search-backend-node@1.3.7
+
+## 0.0.34-next.2
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/backend-defaults@0.7.0-next.1
+ - @backstage/backend-plugin-api@1.1.1-next.1
+ - @backstage/catalog-model@1.7.3-next.0
+ - @backstage/plugin-app-backend@0.4.4-next.1
+ - @backstage/plugin-auth-backend@0.24.2-next.1
+ - @backstage/plugin-auth-node@0.5.6-next.1
+ - @backstage/plugin-catalog-backend@1.30.0-next.1
+ - @backstage/plugin-catalog-backend-module-openapi@0.2.6-next.1
+ - @backstage/plugin-devtools-backend@0.5.1-next.1
+ - @backstage/plugin-events-backend@0.4.1-next.1
+ - @backstage/plugin-kubernetes-backend@0.19.2-next.1
+ - @backstage/plugin-permission-common@0.8.4-next.0
+ - @backstage/plugin-proxy-backend@0.5.10-next.1
+ - @backstage/plugin-scaffolder-backend@1.29.0-next.2
+ - @backstage/plugin-search-backend@1.8.1-next.1
+ - @backstage/plugin-signals-backend@0.3.0-next.2
+ - @backstage/plugin-auth-backend-module-github-provider@0.2.4-next.1
+ - @backstage/plugin-notifications-backend@0.5.1-next.1
+ - @backstage/plugin-permission-backend@0.5.53-next.1
+ - @backstage/plugin-permission-node@0.8.7-next.1
+ - @backstage/plugin-search-backend-node@1.3.7-next.1
+ - @backstage/plugin-techdocs-backend@1.11.5-next.2
+ - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.4-next.1
+ - @backstage/plugin-auth-backend-module-guest-provider@0.2.4-next.1
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.4-next.1
+ - @backstage/plugin-catalog-backend-module-unprocessed@0.5.4-next.1
+ - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.4-next.1
+ - @backstage/plugin-scaffolder-backend-module-github@0.5.5-next.2
+ - @backstage/plugin-scaffolder-backend-module-notifications@0.1.6-next.1
+ - @backstage/plugin-search-backend-module-catalog@0.3.0-next.1
+ - @backstage/plugin-search-backend-module-explore@0.2.7-next.1
+ - @backstage/plugin-search-backend-module-techdocs@0.3.5-next.1
+
## 0.0.34-next.1
### Patch Changes
diff --git a/packages/backend/knip-report.md b/packages/backend/knip-report.md
index a26b412ee9..d24322fd2b 100644
--- a/packages/backend/knip-report.md
+++ b/packages/backend/knip-report.md
@@ -1,12 +1,15 @@
# Knip report
-## Unused dependencies (5)
+## Unused dependencies (8)
| Name | Location | Severity |
| :----------------------------------------------- | :----------- | :------- |
| @backstage/plugin-catalog-backend-module-openapi | package.json | error |
+| @opentelemetry/auto-instrumentations-node | package.json | error |
| @backstage/plugin-search-backend-node | package.json | error |
| @backstage/plugin-permission-common | package.json | error |
+| @opentelemetry/exporter-prometheus | package.json | error |
| @backstage/plugin-permission-node | package.json | error |
-| @backstage/backend-tasks | package.json | error |
+| @opentelemetry/sdk-node | package.json | error |
+| example-app | package.json | error |
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 96e1534fc6..9543dab07f 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "example-backend",
- "version": "0.0.34-next.1",
+ "version": "0.0.35-next.1",
"backstage": {
"role": "backend"
},
diff --git a/packages/canon/.storybook/main.ts b/packages/canon/.storybook/main.ts
index cf7921268e..8bf24a7e23 100644
--- a/packages/canon/.storybook/main.ts
+++ b/packages/canon/.storybook/main.ts
@@ -9,11 +9,7 @@ function getAbsolutePath(value: string): any {
return dirname(require.resolve(join(value, 'package.json')));
}
const config: StorybookConfig = {
- stories: [
- '../docs/**/*.mdx',
- '../src/components/**/*.mdx',
- '../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)',
- ],
+ stories: ['../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
staticDirs: ['../static'],
addons: [
getAbsolutePath('@storybook/addon-webpack5-compiler-swc'),
diff --git a/packages/canon/.storybook/preview.tsx b/packages/canon/.storybook/preview.tsx
index 1ac53acd86..fbc319ccea 100644
--- a/packages/canon/.storybook/preview.tsx
+++ b/packages/canon/.storybook/preview.tsx
@@ -2,9 +2,6 @@ import React from 'react';
import type { Preview, ReactRenderer } from '@storybook/react';
import { withThemeByDataAttribute } from '@storybook/addon-themes';
-// Storybook specific styles
-import '../docs/components/styles.css';
-
// Canon specific styles
import '../src/css/core.css';
import '../src/css/components.css';
@@ -32,43 +29,43 @@ const preview: Preview = {
},
viewport: {
viewports: {
- xs: {
- name: 'XSmall',
+ initial: {
+ name: 'Initial',
styles: {
width: '320px',
height: '100%',
},
},
- small: {
- name: 'Small',
+ xs: {
+ name: 'Extra Small',
styles: {
width: '640px',
height: '100%',
},
},
- medium: {
- name: 'Medium',
+ sm: {
+ name: 'Small',
styles: {
width: '768px',
height: '100%',
},
},
- large: {
- name: 'Large',
+ md: {
+ name: 'Medium',
styles: {
width: '1024px',
height: '100%',
},
},
- xlarge: {
- name: 'XLarge',
+ lg: {
+ name: 'Large',
styles: {
width: '1280px',
height: '100%',
},
},
- '2xl': {
- name: '2XL',
+ xl: {
+ name: 'Extra Large',
styles: {
width: '1536px',
height: '100%',
@@ -88,12 +85,11 @@ const preview: Preview = {
defaultTheme: 'Light',
}),
Story => {
- document.body.style.backgroundColor = 'var(--canon-background)';
+ document.body.style.backgroundColor = 'var(--canon-bg)';
const docsStoryElements = document.getElementsByClassName('docs-story');
Array.from(docsStoryElements).forEach(element => {
- (element as HTMLElement).style.backgroundColor =
- 'var(--canon-background)';
+ (element as HTMLElement).style.backgroundColor = 'var(--canon-bg)';
});
return (
diff --git a/packages/canon/.storybook/themes/backstage.css b/packages/canon/.storybook/themes/backstage.css
index 5777f303b6..653836c558 100644
--- a/packages/canon/.storybook/themes/backstage.css
+++ b/packages/canon/.storybook/themes/backstage.css
@@ -1,18 +1,8 @@
-[data-theme='backstage-light'] {
- /* Colors */
- --canon-accent: #2e77d0;
- --canon-background: #f8f8f8;
- --canon-surface-1: #fff;
- --canon-surface-2: #f4f4f4;
-
- /* Text colors */
- --canon-text-primary: #000;
- --canon-text-primary-on-accent: #fff;
- --canon-text-secondary: #646464;
-
+[data-theme-name='legacy'][data-theme='light'],
+[data-theme-name='legacy'][data-theme='dark'] {
--canon-font-regular: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;
- .cn-button {
+ .canon-Button {
border-radius: 60px;
font-weight: 400;
text-transform: uppercase;
@@ -30,7 +20,7 @@
box-shadow: none;
}
- &.cn-button-primary {
+ &.canon-Button--variant-primary {
color: #fff;
background-color: rgb(21, 58, 102);
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2),
@@ -43,7 +33,7 @@
}
}
- &.cn-button-secondary {
+ &.canon-Button--variant-secondary {
background-color: transparent;
border: 1px solid rgba(31, 84, 147, 0.5);
color: #1f5493;
@@ -54,7 +44,7 @@
}
}
- &.cn-button-tertiary {
+ &.canon-Button--variant-tertiary {
background-color: transparent;
border: none;
color: #1f5493;
@@ -62,15 +52,37 @@
}
}
-[data-theme='backstage-dark'] {
+[data-theme-name='legacy'][data-theme='light'] {
/* Colors */
- --canon-accent: #2e77d0;
- --canon-background: #000;
- --canon-surface-1: #121212;
- --canon-surface-2: #1a1a1a;
+ --canon-bg-accent: #2e77d0;
+ --canon-bg: #f8f8f8;
+ --canon-bg-elevated: #fff;
+ --canon-bg: #f4f4f4;
/* Text colors */
- --canon-text-primary: #fff;
- --canon-text-primary-on-accent: #000;
- --canon-text-secondary: #b3b3b3;
+ --canon-fg-text-primary: #000;
+ --canon-fg-accent: #fff;
+ --canon-fg-text-secondary: #646464;
+}
+
+[data-theme-name='legacy'][data-theme='dark'] {
+ /* Colors */
+ --canon-bg-accent: #fff;
+ --canon-bg: #000;
+ --canon-bg-elevated: #121212;
+ --canon-bg: #1a1a1a;
+
+ /* Borders */
+ --canon-border: rgba(255, 255, 255, 0.2);
+ --canon-border-warning: #f50000;
+ --canon-border-danger: #f87503;
+ --canon-border-focus: #25d262;
+
+ /* States - Add more states */
+ --canon-fg-danger: #f50000;
+
+ /* Text colors */
+ --canon-fg-text-primary: #fff;
+ --canon-fg-accent: #000;
+ --canon-fg-text-secondary: #b3b3b3;
}
diff --git a/packages/canon/CHANGELOG.md b/packages/canon/CHANGELOG.md
new file mode 100644
index 0000000000..dc2a6e2987
--- /dev/null
+++ b/packages/canon/CHANGELOG.md
@@ -0,0 +1,19 @@
+# @backstage/canon
+
+## 0.1.0-next.1
+
+### Minor Changes
+
+- 72c9800: **BREAKING**: Merged the Stack and Inline component into a single component called Flex.
+- 1e4ccce: **BREAKING**: Fixing css structure and making sure that props are applying the correct styles for all responsive values.
+
+### Patch Changes
+
+- 989af25: Removed client directive as they are not needed in React 18.
+- 58ec9e7: Removed older versions of React packages as a preparatory step for upgrading to React 19. This commit does not introduce any functional changes, but removes dependencies on previous React versions, allowing for a cleaner upgrade path in subsequent commits.
+
+## 0.1.0-next.0
+
+### Minor Changes
+
+- 65f4acc: This is the first alpha release for Canon. As part of this release we are introducing 5 layout components and 7 components. All theming is done through CSS variables.
diff --git a/packages/canon/README.md b/packages/canon/README.md
index a8bf36d7be..0783d01736 100644
--- a/packages/canon/README.md
+++ b/packages/canon/README.md
@@ -1,6 +1,6 @@
# @backstage/canon
-_This package was created through the Backstage CLI_.
+Canon is a UI component library for Backstage.
## Installation
@@ -10,3 +10,9 @@ Install the package via Yarn:
cd # if within a monorepo
yarn add @backstage/canon
```
+
+## Documentation
+
+- [Canon Documentation](https://canon.backstage.io)
+- [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md)
+- [Backstage Documentation](https://backstage.io/docs)
diff --git a/packages/canon/docs/Home.mdx b/packages/canon/docs/Home.mdx
deleted file mode 100644
index 5b85ab15ad..0000000000
--- a/packages/canon/docs/Home.mdx
+++ /dev/null
@@ -1,91 +0,0 @@
-import { Unstyled } from '@storybook/blocks';
-import {
- Columns,
- Text,
- ComponentStatus,
- Banner,
- Title,
- Roadmap,
-} from './components';
-import { list } from './components/Roadmap/list';
-
-
-
-
-
-
- Welcome to the Canon, the new design library for Backstage plugins. This
- project is still under active development but we will make sure to document
- the API as we go. We are aiming to improve the general UI of Backstage and
- plugins across Backstage. This new library will take time to build but we are
- building it incrementally with not conflict with the existing theming system.
-
-
-
- This library is still under heavy construction. Please be aware that the API
- will change until we reach a stable release.
-
-
-
- Component Status
-
-
- We are still in the process of documenting the API and building the
- components. You can use the statuses below to see what is ready and what is
- coming soon. If there is a component missing that you need, please let us know
- by opening an issue on GitHub.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Roadmap
-
-
-
-
-
diff --git a/packages/canon/docs/Iconography.mdx b/packages/canon/docs/Iconography.mdx
deleted file mode 100644
index 83d181af12..0000000000
--- a/packages/canon/docs/Iconography.mdx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Unstyled, Source, Meta } from '@storybook/blocks';
-import { Title, Text, IconLibrary } from './components';
-
-
-
-
-
-Iconography
-
-
- All our default icons are provided by [Remix Icon](https://remixicon.com/). We
- don't import all icons to reduce the bundle size but we cherry pick a nice
- selection for you to use in your application. The list of names is set down
- below. To use an icon, you can use the `Icon` component and pass the name of
- the icon you want to use.
-
-
-`} language="tsx" dark />
-
-
-
-
diff --git a/packages/canon/docs/Layout.mdx b/packages/canon/docs/Layout.mdx
deleted file mode 100644
index 9145f71aed..0000000000
--- a/packages/canon/docs/Layout.mdx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Unstyled, Source, Meta } from '@storybook/blocks';
-import { Title, Text, LayoutComponents } from './components';
-import * as Table from './components/Table';
-
-
-
-
-
-Layout
-
- Canon is made for extensibility. We built this library to make it easy for any
- Backstage plugin creator to be able to build their ideas at speed ensuring
- consistency across the rest of your ecosystem. Each component is designed to
- be editable to match your need but sometimes you want to have more control
- over the layout of your page. To help you with that, we created a set of
- layout components that you can use to build your own layouts. All of these
- components are built to extend on our theming system, making it easy for you
- to build your own layouts. Sometimes these components are not enough so we
- created a set of helpers to be used with any CSS-in-JS library.
-
-
-Layout Components
-
-
- We built a couple of layout components to help you build responsive elements
- that will be consistent with the rest of your Backstage instance. These
- components are opinionated and use TypeScript to ensure that the props you
- provide are the ones coming from the theme.
-
-
-
- Hello World
-
- Project 1
- Project 2
-
-`}
- language="tsx"
- dark
-/>
-
-
-
-Layout Helpers
-
-
- Sometimes you want to use global tokens dynamically outside of React
- components. To help you with that we would like to provide a set of helpers
- that you can use in your code. These helpers are not available just yet but we
- are working on it.
-
-
-
diff --git a/packages/canon/docs/Theme.mdx b/packages/canon/docs/Theme.mdx
deleted file mode 100644
index 1ea7c5c4c6..0000000000
--- a/packages/canon/docs/Theme.mdx
+++ /dev/null
@@ -1,231 +0,0 @@
-import { Unstyled, Source, Meta } from '@storybook/blocks';
-import { Title, Text, Chip } from './components';
-import * as Table from './components/Table';
-
-{' '}
-
-
-
-Theming
-
- Backstage ships with a default theme with a light and dark mode variant. The
- themes are provided as a part of the `@backstage/canon` package, which also
- includes utilities for customizing the default theme, or creating completely
- new themes.
-
-
-Light & Dark modes
-
- By default we are supporting both light and dark modes. Each user can opt to
- choose what theme they want to use or to use their system decide what theme to
- use. If you want to create your own theme, you will have to set both light and
- dark themes following the instructions below. If you only set one of them, the
- other mode will fallback to the default theme.
-
-
-How to create your own theme
-
- To create your own theme, you will have to define the variables below. To do
- that, create a theme.css file and import it in your application. Here's an
- example below on how to set your light and dark mode.
-
-
-
-Colors
-
- We provide a set of generic colours tokens that we use across Canon. By
- changing these colours you can easily change the look and feel of your
- application to match your brand.
-
-
-
-
- Prop
- Description
-
-
-
-
-
- --canon-accent
-
- The accent color for the theme.
-
-
-
- --canon-bg
-
- The background color for the theme.
-
-
-
- --canon-surface-1
-
- The first surface color for the theme.
-
-
-
- --canon-surface-2
-
- The second surface color for the theme.
-
-
-
- --canon-outline
-
- The outline color for the theme.
-
-
-
- --canon-outline-focus
-
- The outline focus color for the theme.
-
-
-
- --canon-text-primary
-
- The primary text color for the theme.
-
-
-
- --canon-text-secondary
-
- The secondary text color for the theme.
-
-
-
-
-Typography
-
- We have two fonts that we use across Canon. The first one is the sans-serif
- font that we use for the body of the application. The second one is the
- monospace font that we use for code blocks and tables.
-
-
-
-
-
- Prop
- Description
-
-
-
-
-
- --canon-font-regular
-
- The sans-serif font for the theme.
-
-
-
- --canon-font-mono
-
- The monospace font for the theme.
-
-
-
-
-Spacing
-
- Our default spacing system is made to work in most scenarios. We have 7 scale
- values from `xxs` to `xxl`. We use the values on padding and margin in our
- layout components mostly. If you prefer to use a different spacing system, you
- can do that by changing the values below.
-
-
-
-
-
- Prop
- Description
-
-
-
-
-
- --canon-space-unit
-
-
- The base unit for the spacing system. Default value is `1em`
-
-
-
-
- --canon-space-xxs
-
- Default value is `0.25 x space unit`
-
-
-
- --canon-space-xs
-
- Default value is `0.5 x space unit`
-
-
-
- --canon-space-sm
-
- Default value is `0.75 x space unit`
-
-
-
- --canon-space-md
-
- Default value is `1.25 x space unit`
-
-
-
- --canon-space-lg
-
- Default value is `2 x space unit`
-
-
-
- --canon-space-xl
-
- Default value is `3.25 x space unit`
-
-
-
- --canon-space-xxl
-
- Default value is `5.25 x space unit`
-
-
-
-
-
diff --git a/packages/canon/docs/Typography.mdx b/packages/canon/docs/Typography.mdx
deleted file mode 100644
index 802b9881be..0000000000
--- a/packages/canon/docs/Typography.mdx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Unstyled, Meta, Canvas } from '@storybook/blocks';
-import {
- Columns,
- Text,
- ComponentStatus,
- Banner,
- Title,
- Roadmap,
-} from './components';
-import { list } from './components/Roadmap/list';
-import * as HeadingStories from '../src/components/Heading/Heading.stories';
-import * as TextStories from '../src/components/Text/Text.stories';
-
-
-
-
-
-Typography
-
- Canon offers a suite of typography components designed to seamlessly align
- with the rest of your Backstage instance. While you can customize their
- appearance to match your brand, the underlying API remains consistent and
- unchanged. Each component is built on a responsive structure, allowing you to
- define different typography values for various breakpoints.
-
-
-Heading
-
- Headings are used to structure the content of your page. They are used to
- create a hierarchy of information and to make the content more readable. The
- best way to use add these headings to your page is to import the [Heading
- component](?path=/docs/components-heading--docs).
-
-
-
-
-Text
-
- Canon provides four distinct text variants, each offering different font sizes
- carefully designed to cover the majority of use cases. These variants are
- versatile and can be paired with regular and bold of font weights. You can use
- the [Text component](?path=/docs/components-text--docs) to add text to your
- page.
-
-
-
-
-
diff --git a/packages/canon/docs/components/Banner/styles.css b/packages/canon/docs/components/Banner/styles.css
deleted file mode 100644
index d20e14ce0b..0000000000
--- a/packages/canon/docs/components/Banner/styles.css
+++ /dev/null
@@ -1,37 +0,0 @@
-.banner {
- display: flex;
- align-items: center;
- font-size: 16px;
- line-height: 28px;
- padding: 16px;
- border-radius: 6px;
- margin-bottom: 16px;
- border: 1px solid #e0e0e0;
-
- & > p {
- margin: 0;
- }
-
- &.info {
- background-color: #f2f2f2;
- border-color: #cdcdcd;
- color: #888888;
- }
-
- &.warning {
- background-color: #fff2b9;
- border-color: #ffd000;
- color: #d79927;
- }
-
- & .icon {
- width: 32px;
- height: 32px;
- background-color: rgba(215, 153, 39, 0.2);
- border-radius: 6px;
- margin-right: 16px;
- display: flex;
- align-items: center;
- justify-content: center;
- }
-}
diff --git a/packages/canon/docs/components/ComponentStatus/ComponentStatus.tsx b/packages/canon/docs/components/ComponentStatus/ComponentStatus.tsx
deleted file mode 100644
index 0159e27b32..0000000000
--- a/packages/canon/docs/components/ComponentStatus/ComponentStatus.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2024 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 React from 'react';
-
-export const ComponentStatus = ({
- name,
- status = 'notStarted',
- style,
- link,
-}: {
- name: string;
- status: 'notStarted' | 'inProgress' | 'alpha' | 'beta' | 'stable';
- style?: React.CSSProperties;
- link?: string;
-}) => {
- return (
-
- {link ? (
-
- {name}
-
- ) : (
-
{name}
- )}
-
- {status === 'notStarted' && 'Not Started'}
- {status === 'inProgress' && 'In Progress'}
- {status === 'alpha' && 'Alpha'}
- {status === 'beta' && 'Beta'}
- {status === 'stable' && 'Stable'}
-
-
- );
-};
diff --git a/packages/canon/docs/components/ComponentStatus/styles.css b/packages/canon/docs/components/ComponentStatus/styles.css
deleted file mode 100644
index 6ef02ccf3f..0000000000
--- a/packages/canon/docs/components/ComponentStatus/styles.css
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2024 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.
- */
-
-.component-status {
- display: flex;
- justify-content: space-between;
-
- & .title {
- color: #3b59ff;
- font-size: 16px;
- font-weight: 400;
- text-decoration: none;
- }
-
- & .pill {
- display: inline-flex;
- align-items: center;
- color: #000;
- border-radius: 40px;
- padding: 0px 8px;
- height: 24px;
- font-size: 12px;
- font-weight: 600;
- border-style: solid;
- border-width: 1px;
- margin-left: 8px;
-
- &.notStarted {
- background-color: #f2f2f2;
- border-color: #cdcdcd;
- color: #888888;
- }
-
- &.inProgress {
- background-color: #fff2b9;
- border-color: #ffd000;
- color: #d79927;
- }
-
- &.alpha {
- background-color: #d7f9d7;
- border-color: #4ed14a;
- color: #3a9837;
- }
-
- &.beta {
- background-color: #d7f9d7;
- border-color: #4ed14a;
- color: #3a9837;
- }
-
- &.stable {
- background-color: #d7f9d7;
- border-color: #4ed14a;
- color: #3a9837;
- }
- }
-}
diff --git a/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx b/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx
deleted file mode 100644
index 56f389a389..0000000000
--- a/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2024 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 React from 'react';
-import { BoxSvg } from './svgs/box';
-import { StackSvg } from './svgs/stack';
-import { GridSvg } from './svgs/grid';
-import { InlineSvg } from './svgs/inline';
-import { ContainerSvg } from './svgs/container';
-
-export const LayoutComponents = () => {
- return (
-
-
-
-
-
-
Box
-
The most basic layout component
-
-
-
-
-
-
Stack
-
Arrange your components vertically
-
-
-
-
-
-
Grid
-
Arrange your components in a grid
-
-
-
-
-
-
Inline
-
Arrange your components in a row
-
-
-
-
-
-
Container
-
A container for your components
-
-
- );
-};
diff --git a/packages/canon/docs/components/PropsTable/PropsTable.tsx b/packages/canon/docs/components/PropsTable/PropsTable.tsx
deleted file mode 100644
index a3dc9e271c..0000000000
--- a/packages/canon/docs/components/PropsTable/PropsTable.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2024 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 React from 'react';
-import * as Table from '..';
-import { Chip } from '..';
-
-// Modify the PropsTable component to accept a generic type
-export const PropsTable = >({
- data,
-}: {
- data: T;
-}) => {
- return (
-
-
-
- Prop
- Type
- Responsive
-
-
-
- {Object.keys(data).map(n => (
-
-
- {n}
-
-
- {Array.isArray(data[n].type) ? (
- data[n].type.map((t: any) => {t})
- ) : (
- {data[n].type}
- )}
-
-
- {data[n].responsive ? 'Yes' : 'No'}
-
-
- ))}
-
-
- );
-};
diff --git a/packages/canon/docs/components/PropsTable/getProps.ts b/packages/canon/docs/components/PropsTable/getProps.ts
deleted file mode 100644
index 5773eaeb27..0000000000
--- a/packages/canon/docs/components/PropsTable/getProps.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2024 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.
- */
-export function getProps(styles: Record) {
- return Object.keys(styles).reduce(
- (acc: Record, n) => {
- const style = styles[n];
-
- let values: string[] = [];
-
- if (style.values) {
- // If values exist, use them
- values = Object.keys(style.values);
- } else if (style.mappings && style.mappings.length > 0) {
- // If mappings exist, use the first mapping's values
- const firstMapping = style.mappings[0];
- values = Object.keys(styles[firstMapping].values);
- } else {
- // Default to an empty array if neither values nor mappings exist
- values = [];
- }
-
- acc[n] = {
- type: values,
- responsive: true,
- };
- return acc;
- },
- {} as Record,
- );
-}
diff --git a/packages/canon/docs/components/Table/styles.css b/packages/canon/docs/components/Table/styles.css
deleted file mode 100644
index ed56774a85..0000000000
--- a/packages/canon/docs/components/Table/styles.css
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2024 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.
- */
-
-.sb-table-wrapper {
- border: 1px solid #e7e7e7;
- border-radius: 4px;
- overflow: hidden;
-
- & .sb-table {
- width: 100%;
- margin: 0 !important;
- padding: 0 !important;
- border-spacing: 0px;
- border-collapse: collapse;
- }
-
- & .sb-table-cell {
- padding: 12px 16px !important;
- border: none !important;
- text-align: left;
- background-color: white !important;
- font-size: 16px;
-
- & p {
- margin: 0;
- }
- }
-
- & .sb-table-header-cell {
- background-color: #f5f5f5 !important;
- border-bottom: 1px solid #e7e7e7 !important;
- font-weight: 500;
- font-size: 14px;
- }
-
- & .sb-table-row {
- border: none;
- border-bottom: 1px solid #e7e7e7;
- &:last-child {
- border-bottom: none;
- }
- }
-
- & .sb-table-chip {
- display: inline-block;
- font-size: 14px !important;
- border: 1px solid #e7e7e7;
- border-radius: 6px;
- padding: 0px 6px;
- height: 24px;
- }
-
- & .sb-table-type {
- display: flex;
- flex-wrap: wrap;
- flex-direction: row;
- gap: 8px;
- }
-}
diff --git a/packages/canon/docs/components/index.ts b/packages/canon/docs/components/index.ts
deleted file mode 100644
index 0e5ff2e325..0000000000
--- a/packages/canon/docs/components/index.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2024 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.
- */
-
-export * from './Banner';
-export * from './Chip';
-export * from './Columns';
-export * from './ComponentStatus';
-export * from './IconLibrary';
-export * from './LayoutComponents';
-export * from './PropsTable';
-export * from './Roadmap';
-export * from './Table';
-export * from './Text';
-export * from './Title';
diff --git a/packages/canon/docs/components/styles.css b/packages/canon/docs/components/styles.css
deleted file mode 100644
index 706b1626b3..0000000000
--- a/packages/canon/docs/components/styles.css
+++ /dev/null
@@ -1,15 +0,0 @@
-.sbdocs-content {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
- Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
-}
-
-@import './Banner/styles.css';
-@import './Chip/styles.css';
-@import './Columns/styles.css';
-@import './ComponentStatus/styles.css';
-@import './IconLibrary/styles.css';
-@import './LayoutComponents/styles.css';
-@import './Roadmap/styles.css';
-@import './Table/styles.css';
-@import './Text/styles.css';
-@import './Title/styles.css';
diff --git a/packages/canon/package.json b/packages/canon/package.json
index 23c40300f1..54efbe550e 100644
--- a/packages/canon/package.json
+++ b/packages/canon/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/canon",
- "version": "0.0.0",
+ "version": "0.1.0-next.1",
"backstage": {
"role": "web-library"
},
@@ -9,11 +9,10 @@
"main": "dist/index.esm.js",
"types": "dist/index.d.ts"
},
- "private": true,
"keywords": [
"backstage"
],
- "homepage": "https://backstage.io",
+ "homepage": "https://canon.backstage.io",
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
@@ -27,7 +26,9 @@
"dist"
],
"scripts": {
- "build": "backstage-cli package build",
+ "build": "yarn build:app && yarn build:css",
+ "build:app": "backstage-cli package build",
+ "build:css": "node scripts/build-css.mjs",
"build-storybook": "storybook build",
"clean": "backstage-cli package clean",
"lint": "backstage-cli package lint",
@@ -37,37 +38,41 @@
"test": "backstage-cli package test"
},
"dependencies": {
- "@base-ui-components/react": "^1.0.0-alpha.4",
- "@remixicon/react": "^4.5.0"
+ "@base-ui-components/react": "^1.0.0-alpha.5",
+ "@remixicon/react": "^4.5.0",
+ "clsx": "^2.1.1"
},
"devDependencies": {
"@backstage/cli": "workspace:^",
"@chromatic-com/storybook": "^3.2.2",
- "@storybook/addon-essentials": "^8.4.7",
- "@storybook/addon-interactions": "^8.4.7",
+ "@storybook/addon-essentials": "^8.5.0",
+ "@storybook/addon-interactions": "^8.5.0",
"@storybook/addon-styling-webpack": "^1.0.1",
- "@storybook/addon-themes": "^8.4.7",
- "@storybook/addon-webpack5-compiler-swc": "^1.0.5",
- "@storybook/blocks": "^8.4.7",
- "@storybook/react": "^8.4.7",
- "@storybook/react-webpack5": "^8.4.7",
- "@storybook/test": "^8.4.7",
+ "@storybook/addon-themes": "^8.5.0",
+ "@storybook/addon-webpack5-compiler-swc": "^2.0.0",
+ "@storybook/blocks": "^8.5.0",
+ "@storybook/react": "^8.5.0",
+ "@storybook/react-webpack5": "^8.5.0",
+ "@storybook/test": "^8.5.0",
"@testing-library/jest-dom": "^6.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
+ "chalk": "^5.4.1",
"eslint-plugin-storybook": "^0.11.1",
+ "glob": "^11.0.1",
"globals": "^15.11.0",
+ "lightningcss": "^1.29.1",
"mini-css-extract-plugin": "^2.9.2",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-router-dom": "^6.3.0",
- "storybook": "^8.4.7"
+ "storybook": "^8.5.0"
},
"peerDependencies": {
- "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
- "react": "^16.13.1 || ^17.0.0 || ^18.0.0",
- "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
- "react-router-dom": "6.0.0-beta.0 || ^6.3.0"
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0",
+ "react-router-dom": "^6.3.0"
},
"peerDependenciesMeta": {
"@types/react": {
diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md
index e725d0ac8b..ef59d46f68 100644
--- a/packages/canon/report.api.md
+++ b/packages/canon/report.api.md
@@ -5,14 +5,25 @@
```ts
///
+import type { CSSProperties } from 'react';
+import { Field as Field_2 } from '@base-ui-components/react/field';
import { ForwardRefExoticComponent } from 'react';
+import { Input as Input_2 } from '@base-ui-components/react/input';
import { default as React_2 } from 'react';
import * as React_3 from 'react';
+import { ReactNode } from 'react';
import { RefAttributes } from 'react';
// @public (undocumented)
export type AlignItems = 'stretch' | 'start' | 'center' | 'end';
+// @public (undocumented)
+export type ArbitraryStylingPropDef = {
+ className: string;
+ customProperties: `--${string}`[];
+ parseValue?: (value: string) => string | undefined;
+};
+
// @public (undocumented)
export type AsProps =
| 'div'
@@ -32,6 +43,14 @@ export type AsProps =
| 'dl'
| 'dt';
+// @public (undocumented)
+export type BooleanPropDef = {
+ type: 'boolean';
+ default?: boolean;
+ required?: boolean;
+ className?: string;
+};
+
// @public (undocumented)
export type Border = 'none' | 'base' | 'error' | 'warning' | 'selected';
@@ -52,19 +71,50 @@ export const Box: ForwardRefExoticComponent<
>;
// @public (undocumented)
-export interface BoxProps extends UtilityProps {
+export type BoxOwnProps = GetPropDefTypes;
+
+// @public (undocumented)
+export const boxPropDefs: {
+ as: {
+ type: 'enum';
+ values: readonly ['div', 'span'];
+ default: 'div';
+ };
+};
+
+// @public (undocumented)
+export interface BoxProps extends SpaceProps {
// (undocumented)
- as?: keyof JSX.IntrinsicElements;
+ as?: BoxOwnProps['as'];
// (undocumented)
children?: React.ReactNode;
// (undocumented)
className?: string;
// (undocumented)
+ display?: DisplayProps['display'];
+ // (undocumented)
+ height?: HeightProps['height'];
+ // (undocumented)
+ maxHeight?: HeightProps['maxHeight'];
+ // (undocumented)
+ maxWidth?: WidthProps['maxWidth'];
+ // (undocumented)
+ minHeight?: HeightProps['minHeight'];
+ // (undocumented)
+ minWidth?: WidthProps['minWidth'];
+ // (undocumented)
+ position?: PositionProps['position'];
+ // (undocumented)
style?: React.CSSProperties;
+ // (undocumented)
+ width?: WidthProps['width'];
}
// @public (undocumented)
-export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
+export type Breakpoint = 'initial' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
+
+// @public (undocumented)
+export const breakpoints: Breakpoint[];
// @public (undocumented)
export const Button: React_2.ForwardRefExoticComponent<
@@ -76,6 +126,8 @@ export interface ButtonProps {
// (undocumented)
children: React.ReactNode;
// (undocumented)
+ className?: string;
+ // (undocumented)
disabled?: boolean;
// (undocumented)
iconEnd?: IconNames;
@@ -84,6 +136,8 @@ export interface ButtonProps {
// (undocumented)
size?: 'small' | 'medium' | Partial>;
// (undocumented)
+ style?: React.CSSProperties;
+ // (undocumented)
variant?:
| 'primary'
| 'secondary'
@@ -91,6 +145,23 @@ export interface ButtonProps {
| Partial>;
}
+// @public (undocumented)
+export interface CanonContextProps {
+ // (undocumented)
+ icons: IconMap;
+}
+
+// @public (undocumented)
+export const CanonProvider: (props: CanonProviderProps) => React_2.JSX.Element;
+
+// @public (undocumented)
+export interface CanonProviderProps {
+ // (undocumented)
+ children?: ReactNode;
+ // (undocumented)
+ overrides?: Partial>;
+}
+
// @public (undocumented)
export const Checkbox: React_2.ForwardRefExoticComponent<
CheckboxProps & React_2.RefAttributes
@@ -124,8 +195,8 @@ export interface CheckboxProps {
export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto';
// @public (undocumented)
-export const Container: React_2.ForwardRefExoticComponent<
- ContainerProps & React_2.RefAttributes
+export const Container: ForwardRefExoticComponent<
+ ContainerProps & RefAttributes
>;
// @public (undocumented)
@@ -135,17 +206,17 @@ export interface ContainerProps {
// (undocumented)
className?: string;
// (undocumented)
- marginBottom?: SpaceProps['marginBottom'];
+ mb?: SpaceProps['mb'];
// (undocumented)
- marginTop?: SpaceProps['marginTop'];
+ mt?: SpaceProps['mt'];
// (undocumented)
- marginY?: SpaceProps['marginY'];
+ my?: SpaceProps['my'];
// (undocumented)
- paddingBottom?: SpaceProps['paddingBottom'];
+ pb?: SpaceProps['pb'];
// (undocumented)
- paddingTop?: SpaceProps['paddingTop'];
+ pt?: SpaceProps['pt'];
// (undocumented)
- paddingY?: SpaceProps['paddingY'];
+ py?: SpaceProps['py'];
// (undocumented)
style?: React.CSSProperties;
}
@@ -153,12 +224,162 @@ export interface ContainerProps {
// @public (undocumented)
export type Display = 'none' | 'flex' | 'block' | 'inline';
+// @public (undocumented)
+export const displayPropDefs: {
+ display: {
+ type: 'enum';
+ className: string;
+ values: readonly ['none', 'inline', 'inline-block', 'block'];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export type DisplayProps = GetPropDefTypes;
+
+// @public (undocumented)
+export type EnumOrStringPropDef = {
+ type: 'enum | string';
+ values: readonly T[];
+ default?: T | string;
+ required?: boolean;
+};
+
+// @public (undocumented)
+export type EnumPropDef = {
+ type: 'enum';
+ values: readonly T[];
+ default?: T;
+ required?: boolean;
+};
+
+// @public (undocumented)
+export const Field: {
+ Root: React_2.ForwardRefExoticComponent<
+ Omit, 'ref'> &
+ React_2.RefAttributes
+ >;
+ Label: React_2.ForwardRefExoticComponent<
+ Omit, 'ref'> &
+ React_2.RefAttributes
+ >;
+ Description: React_2.ForwardRefExoticComponent<
+ Omit<
+ Field_2.Description.Props & React_2.RefAttributes,
+ 'ref'
+ > &
+ React_2.RefAttributes
+ >;
+ Error: React_2.ForwardRefExoticComponent<
+ Omit, 'ref'> &
+ React_2.RefAttributes
+ >;
+ Validity: ({
+ children,
+ className,
+ ...props
+ }: Field_2.Validity.Props & {
+ className?: string | undefined;
+ }) => React_2.JSX.Element;
+};
+
+// @public (undocumented)
+export const Flex: ForwardRefExoticComponent<
+ FlexProps & RefAttributes
+>;
+
// @public (undocumented)
export type FlexDirection = 'row' | 'column';
+// @public (undocumented)
+export type FlexOwnProps = GetPropDefTypes;
+
+// @public (undocumented)
+export const flexPropDefs: {
+ align: {
+ type: 'enum';
+ className: string;
+ values: readonly ['start', 'center', 'end', 'baseline', 'stretch'];
+ responsive: true;
+ };
+ direction: {
+ type: 'enum';
+ className: string;
+ values: readonly ['row', 'column', 'row-reverse', 'column-reverse'];
+ responsive: true;
+ };
+ justify: {
+ type: 'enum';
+ className: string;
+ values: readonly ['start', 'center', 'end', 'between'];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export interface FlexProps extends SpaceProps {
+ // (undocumented)
+ align?: FlexOwnProps['align'];
+ // (undocumented)
+ children: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ direction?: FlexOwnProps['direction'];
+ // (undocumented)
+ gap?: GapProps['gap'];
+ // (undocumented)
+ justify?: FlexOwnProps['justify'];
+ // (undocumented)
+ style?: React.CSSProperties;
+}
+
// @public (undocumented)
export type FlexWrap = 'wrap' | 'nowrap' | 'wrap-reverse';
+// @public (undocumented)
+export const gapPropDefs: {
+ gap: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--gap'[];
+ values: string[];
+ responsive: true;
+ default: string;
+ };
+};
+
+// @public (undocumented)
+export type GapProps = GetPropDefTypes;
+
+// @public (undocumented)
+export type GetPropDefType = Def extends BooleanPropDef
+ ? Def extends ResponsivePropDef
+ ? Responsive
+ : boolean
+ : Def extends StringPropDef
+ ? Def extends ResponsivePropDef
+ ? Responsive
+ : string
+ : Def extends ReactNodePropDef
+ ? Def extends ResponsivePropDef
+ ? Responsive
+ : React_2.ReactNode
+ : Def extends EnumOrStringPropDef
+ ? Def extends ResponsivePropDef
+ ? Responsive
+ : string | Type
+ : Def extends EnumPropDef
+ ? Def extends ResponsivePropDef
+ ? Responsive
+ : Type
+ : never;
+
+// @public (undocumented)
+export type GetPropDefTypes = {
+ [K in keyof P]?: GetPropDefType
;
+};
+
// @public (undocumented)
export const Grid: ForwardRefExoticComponent<
GridProps & RefAttributes
@@ -168,24 +389,144 @@ export const Grid: ForwardRefExoticComponent<
>;
};
+// @public (undocumented)
+export type GridItemOwnProps = GetPropDefTypes;
+
+// @public (undocumented)
+export const gridItemPropDefs: {
+ colSpan: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--col-span'[];
+ values: readonly [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ 'auto',
+ ];
+ responsive: true;
+ };
+ colEnd: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--col-end'[];
+ values: readonly [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ 'auto',
+ ];
+ responsive: true;
+ };
+ colStart: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--col-start'[];
+ values: readonly [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ 'auto',
+ ];
+ responsive: true;
+ };
+ rowSpan: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--row-span'[];
+ values: readonly [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ 'auto',
+ ];
+ responsive: true;
+ };
+};
+
// @public (undocumented)
export interface GridItemProps {
// (undocumented)
- children: React.ReactNode;
+ children?: React.ReactNode;
// (undocumented)
className?: string;
// (undocumented)
- colEnd?: UtilityProps['colEnd'];
+ colEnd?: GridItemOwnProps['colEnd'];
// (undocumented)
- colSpan?: UtilityProps['colSpan'];
+ colSpan?: GridItemOwnProps['colSpan'];
// (undocumented)
- colStart?: UtilityProps['colStart'];
+ colStart?: GridItemOwnProps['colStart'];
// (undocumented)
- rowSpan?: UtilityProps['rowSpan'];
+ rowSpan?: GridItemOwnProps['rowSpan'];
// (undocumented)
style?: React.CSSProperties;
}
+// @public (undocumented)
+export type GridOwnProps = GetPropDefTypes;
+
+// @public (undocumented)
+export const gridPropDefs: {
+ columns: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--columns'[];
+ values: readonly [
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '10',
+ '11',
+ '12',
+ 'auto',
+ ];
+ responsive: true;
+ default: string;
+ };
+};
+
// @public (undocumented)
export interface GridProps extends SpaceProps {
// (undocumented)
@@ -193,13 +534,69 @@ export interface GridProps extends SpaceProps {
// (undocumented)
className?: string;
// (undocumented)
- columns?: UtilityProps['columns'];
+ columns?: GridOwnProps['columns'];
// (undocumented)
- gap?: UtilityProps['gap'];
+ gap?: GapProps['gap'];
// (undocumented)
style?: React.CSSProperties;
}
+// @public (undocumented)
+export const Heading: React_2.ForwardRefExoticComponent<
+ HeadingProps & React_2.RefAttributes
+>;
+
+// @public (undocumented)
+export interface HeadingProps {
+ // (undocumented)
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+ // (undocumented)
+ children: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ style?: React.CSSProperties;
+ // (undocumented)
+ variant?:
+ | 'display'
+ | 'title1'
+ | 'title2'
+ | 'title3'
+ | 'title4'
+ | 'title5'
+ | Partial<
+ Record<
+ Breakpoint,
+ 'display' | 'title1' | 'title2' | 'title3' | 'title4' | 'title5'
+ >
+ >;
+}
+
+// @public (undocumented)
+export const heightPropDefs: {
+ height: {
+ type: 'string';
+ className: string;
+ customProperties: '--height'[];
+ responsive: true;
+ };
+ minHeight: {
+ type: 'string';
+ className: string;
+ customProperties: '--min-height'[];
+ responsive: true;
+ };
+ maxHeight: {
+ type: 'string';
+ className: string;
+ customProperties: '--max-height'[];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export type HeightProps = GetPropDefTypes;
+
// @public (undocumented)
export const Icon: (props: IconProps) => React_2.JSX.Element;
@@ -222,45 +619,33 @@ export type IconNames =
| 'chevronRight'
| 'chevronUp'
| 'cloud'
+ | 'externalLink'
| 'heart'
+ | 'moon'
| 'plus'
+ | 'sun'
| 'trash';
// @public (undocumented)
export type IconProps = {
name: IconNames;
size?: number;
+ className?: string;
+ style?: React.CSSProperties;
};
// @public (undocumented)
-export const Inline: ForwardRefExoticComponent<
- InlineProps & RefAttributes
+export const icons: IconMap;
+
+// @public (undocumented)
+export const Input: React_2.ForwardRefExoticComponent<
+ InputProps & React_2.RefAttributes
>;
// @public (undocumented)
-export interface InlineProps extends SpaceProps {
+export interface InputProps extends Omit {
// (undocumented)
- align?:
- | 'left'
- | 'center'
- | 'right'
- | Partial>;
- // (undocumented)
- alignY?:
- | 'top'
- | 'center'
- | 'bottom'
- | Partial>;
- // (undocumented)
- as?: AsProps;
- // (undocumented)
- children: React.ReactNode;
- // (undocumented)
- className?: string;
- // (undocumented)
- gap?: UtilityProps['gap'];
- // (undocumented)
- style?: React.CSSProperties;
+ size?: 'sm' | 'md';
}
// @public (undocumented)
@@ -273,64 +658,230 @@ export type JustifyContent =
| 'between';
// @public (undocumented)
-export type Space = 'none' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
+export const marginPropDefs: (spacingValues: string[]) => {
+ m: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: '--m'[];
+ responsive: true;
+ };
+ mx: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: ('--ml' | '--mr')[];
+ responsive: true;
+ };
+ my: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: ('--mt' | '--mb')[];
+ responsive: true;
+ };
+ mt: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: '--mt'[];
+ responsive: true;
+ };
+ mr: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: '--mr'[];
+ responsive: true;
+ };
+ mb: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: '--mb'[];
+ responsive: true;
+ };
+ ml: {
+ type: 'enum | string';
+ values: string[];
+ className: string;
+ customProperties: '--ml'[];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export type MarginProps = GetPropDefTypes;
+
+// @public (undocumented)
+export type NonStylingPropDef = {
+ className?: never;
+ customProperties?: never;
+ parseValue?: never;
+};
+
+// @public (undocumented)
+export const paddingPropDefs: (spacingValues: string[]) => {
+ p: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--p'[];
+ values: string[];
+ responsive: true;
+ };
+ px: {
+ type: 'enum | string';
+ className: string;
+ customProperties: ('--pl' | '--pr')[];
+ values: string[];
+ responsive: true;
+ };
+ py: {
+ type: 'enum | string';
+ className: string;
+ customProperties: ('--pt' | '--pb')[];
+ values: string[];
+ responsive: true;
+ };
+ pt: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--pt'[];
+ values: string[];
+ responsive: true;
+ };
+ pr: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--pr'[];
+ values: string[];
+ responsive: true;
+ };
+ pb: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--pb'[];
+ values: string[];
+ responsive: true;
+ };
+ pl: {
+ type: 'enum | string';
+ className: string;
+ customProperties: '--pl'[];
+ values: string[];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export type PaddingProps = GetPropDefTypes;
+
+// @public (undocumented)
+export const positionPropDefs: {
+ position: {
+ type: 'enum';
+ className: string;
+ values: readonly ['static', 'relative', 'absolute', 'fixed', 'sticky'];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export type PositionProps = GetPropDefTypes;
+
+// @public (undocumented)
+export type PropDef = RegularPropDef | ResponsivePropDef;
+
+// @public (undocumented)
+export type ReactNodePropDef = {
+ type: 'ReactNode';
+ default?: React_2.ReactNode;
+ required?: boolean;
+};
+
+// @public (undocumented)
+export type RegularPropDef =
+ | ReactNodePropDef
+ | BooleanPropDef
+ | (StringPropDef & ArbitraryStylingPropDef)
+ | (StringPropDef & NonStylingPropDef)
+ | (EnumPropDef & StylingPropDef)
+ | (EnumPropDef & NonStylingPropDef)
+ | (EnumOrStringPropDef & ArbitraryStylingPropDef)
+ | (EnumOrStringPropDef & NonStylingPropDef);
+
+// @public (undocumented)
+export type Responsive = T | Partial>;
+
+// @public (undocumented)
+export type ResponsivePropDef = RegularPropDef & {
+ responsive: true;
+};
+
+// @public (undocumented)
+export type Space =
+ | '0.5'
+ | '1'
+ | '1.5'
+ | '2'
+ | '3'
+ | '4'
+ | '5'
+ | '6'
+ | '7'
+ | '8'
+ | '9'
+ | '10'
+ | '11'
+ | '12'
+ | '13'
+ | '14'
+ | string;
// @public (undocumented)
export interface SpaceProps {
// (undocumented)
- margin?: Space | Partial>;
+ m?: Responsive;
// (undocumented)
- marginBottom?: Space | Partial>;
+ mb?: Responsive;
// (undocumented)
- marginLeft?: Space | Partial>;
+ ml?: Responsive;
// (undocumented)
- marginRight?: Space | Partial>;
+ mr?: Responsive;
// (undocumented)
- marginTop?: Space | Partial>;
+ mt?: Responsive;
// (undocumented)
- marginX?: Space | Partial>;
+ mx?: Responsive;
// (undocumented)
- marginY?: Space | Partial>;
+ my?: Responsive;
// (undocumented)
- padding?: Space | Partial>;
+ p?: Responsive;
// (undocumented)
- paddingBottom?: Space | Partial>;
+ pb?: Responsive;
// (undocumented)
- paddingLeft?: Space | Partial>;
+ pl?: Responsive;
// (undocumented)
- paddingRight?: Space | Partial>;
+ pr?: Responsive;
// (undocumented)
- paddingTop?: Space | Partial>;
+ pt?: Responsive;
// (undocumented)
- paddingX?: Space | Partial>;
+ px?: Responsive;
// (undocumented)
- paddingY?: Space | Partial>;
+ py?: Responsive;
}
// @public (undocumented)
-export const Stack: ForwardRefExoticComponent<
- StackProps & RefAttributes
->;
+export type StringPropDef = {
+ type: 'string';
+ default?: string;
+ required?: boolean;
+};
// @public (undocumented)
-export interface StackProps extends SpaceProps {
- // (undocumented)
- align?:
- | 'left'
- | 'center'
- | 'right'
- | Partial>;
- // (undocumented)
- as?: AsProps;
- // (undocumented)
- children: React.ReactNode;
- // (undocumented)
- className?: string;
- // (undocumented)
- gap?: UtilityProps['gap'];
- // (undocumented)
- style?: React.CSSProperties;
-}
+export type StylingPropDef = {
+ className: string;
+ parseValue?: (value: string) => string | undefined;
+};
// @public (undocumented)
export const Table: React_3.ForwardRefExoticComponent<
@@ -374,33 +925,86 @@ export const TableRow: React_3.ForwardRefExoticComponent<
React_3.RefAttributes
>;
+// @public (undocumented)
+const Text_2: React_2.ForwardRefExoticComponent<
+ TextProps & React_2.RefAttributes
+>;
+export { Text_2 as Text };
+
+// @public (undocumented)
+export interface TextProps {
+ // (undocumented)
+ children: ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ style?: CSSProperties;
+ // (undocumented)
+ variant?:
+ | 'subtitle'
+ | 'body'
+ | 'caption'
+ | 'label'
+ | Partial>;
+ // (undocumented)
+ weight?: 'regular' | 'bold' | Partial>;
+}
+
+// @public (undocumented)
+export const useCanon: () => CanonContextProps;
+
// @public (undocumented)
export interface UtilityProps extends SpaceProps {
// (undocumented)
- alignItems?: AlignItems | Partial>;
+ alignItems?: Responsive;
// (undocumented)
- border?: Border | Partial>;
+ border?: Responsive;
// (undocumented)
- borderRadius?: BorderRadius | Partial>;
+ borderRadius?: Responsive;
// (undocumented)
- colEnd?: Columns | 'auto' | Partial>;
+ colEnd?: Responsive;
// (undocumented)
- colSpan?: Columns | 'full' | Partial>;
+ colSpan?: Responsive;
// (undocumented)
- colStart?: Columns | 'auto' | Partial>;
+ colStart?: Responsive;
// (undocumented)
- columns?: Columns | Partial>;
+ columns?: Responsive;
// (undocumented)
- display?: Display | Partial>;
+ display?: Responsive;
// (undocumented)
- flexDirection?: FlexDirection | Partial>;
+ flexDirection?: Responsive;
// (undocumented)
- flexWrap?: FlexWrap | Partial>;
+ flexWrap?: Responsive;
// (undocumented)
- gap?: Space | Partial>;
+ gap?: Responsive;
// (undocumented)
- justifyContent?: JustifyContent | Partial>;
+ justifyContent?: Responsive;
// (undocumented)
- rowSpan?: Columns | 'full' | Partial>;
+ rowSpan?: Responsive;
}
+
+// @public (undocumented)
+export const widthPropDefs: {
+ width: {
+ type: 'string';
+ className: string;
+ customProperties: '--width'[];
+ responsive: true;
+ };
+ minWidth: {
+ type: 'string';
+ className: string;
+ customProperties: '--min-width'[];
+ responsive: true;
+ };
+ maxWidth: {
+ type: 'string';
+ className: string;
+ customProperties: '--max-width'[];
+ responsive: true;
+ };
+};
+
+// @public (undocumented)
+export type WidthProps = GetPropDefTypes;
```
diff --git a/packages/canon/scripts/build-css.mjs b/packages/canon/scripts/build-css.mjs
new file mode 100644
index 0000000000..f0ca17c73e
--- /dev/null
+++ b/packages/canon/scripts/build-css.mjs
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2024 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.
+ */
+
+/* eslint-disable no-restricted-imports */
+import { transform, bundle } from 'lightningcss';
+import fs from 'fs';
+import path from 'path';
+import chalk from 'chalk';
+import { glob } from 'glob';
+/* eslint-enable no-restricted-imports */
+
+// Check if core.css and components.css exist
+const cssDir = 'src/css';
+const distDir = 'dist/css';
+const componentsDir = 'src/components';
+
+// Core files
+const cssFiles = [
+ { path: `${cssDir}/core.css`, newName: 'core.css' },
+ { path: `${cssDir}/components.css`, newName: 'components.css' },
+];
+
+// Components files
+const componentsFiles = glob
+ .sync('**/*.css', { cwd: componentsDir })
+ .map(file => {
+ const folderName = file.split('/')[0].toLocaleLowerCase('en-US');
+ return { path: `${componentsDir}/${file}`, newName: `${folderName}.css` };
+ });
+
+// Combine core and components files
+cssFiles.push(...componentsFiles);
+
+// Check if files exist
+cssFiles.forEach(file => {
+ if (!fs.existsSync(file.path)) {
+ console.error(`${file.originalName} does not exist`);
+ process.exit(1);
+ }
+});
+
+// Ensure the dist/css directory exists
+if (!fs.existsSync(distDir)) {
+ fs.mkdirSync(distDir, { recursive: true });
+}
+
+// Bundle and transform files
+cssFiles.forEach(file => {
+ let { code: bundleCode } = bundle({
+ filename: file.path,
+ });
+
+ let { code, map } = transform({
+ filename: `${distDir}/${file.newName}`,
+ code: bundleCode,
+ minify: true,
+ sourceMap: true,
+ });
+
+ fs.writeFileSync(`${distDir}/${file.newName}`, code);
+ fs.writeFileSync(`${distDir}/${file.newName}.map`, map);
+
+ console.log(chalk.blue('CSS bundled: ') + file.newName);
+});
+
+console.log(chalk.green('CSS files bundled successfully!'));
diff --git a/packages/canon/src/components/Box/Box.props.ts b/packages/canon/src/components/Box/Box.props.ts
new file mode 100644
index 0000000000..3cf0291e43
--- /dev/null
+++ b/packages/canon/src/components/Box/Box.props.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2025 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 type { PropDef, GetPropDefTypes } from '../../props/prop-def';
+
+const as = ['div', 'span'] as const;
+
+/** @public */
+const boxPropDefs = {
+ as: { type: 'enum', values: as, default: 'div' },
+} satisfies {
+ as: PropDef<(typeof as)[number]>;
+};
+
+// Use all of the imported prop defs to ensure that JSDoc works
+/** @public */
+type BoxOwnProps = GetPropDefTypes;
+
+export { boxPropDefs };
+export type { BoxOwnProps };
diff --git a/packages/canon/src/components/Box/Box.stories.tsx b/packages/canon/src/components/Box/Box.stories.tsx
index bd4e597fa0..7b9aecca1a 100644
--- a/packages/canon/src/components/Box/Box.stories.tsx
+++ b/packages/canon/src/components/Box/Box.stories.tsx
@@ -17,15 +17,11 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Box } from './Box';
-import { Stack } from '../Stack';
-import { Inline } from '../Inline';
+import { Flex } from '../Flex';
const meta = {
title: 'Components/Box',
component: Box,
- parameters: {
- layout: 'centered',
- },
argTypes: {
as: {
control: { type: 'select' },
@@ -40,149 +36,66 @@ const meta = {
export default meta;
type Story = StoryObj;
-export const Basic: Story = {
+const Card = () => {
+ return (
+
+ );
+};
+
+export const Default: Story = {
args: {
- style: {
- background: '#1f47ff',
- color: 'white',
- padding: '4px 8px',
- borderRadius: '4px',
- },
- children: 'Basic Box',
+ children: ,
+ display: 'inline',
},
};
+const CardDisplay = ({ children }: { children?: React.ReactNode }) => {
+ return (
+
+ {children}
+
+ );
+};
+
export const Display: Story = {
- args: {
- style: {
- ...Basic.args?.style,
- },
- },
render: args => (
-
-
+
+