@backstage/frontend-plugin-api 0.16.0-next.2 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @backstage/frontend-plugin-api
2
2
 
3
+ ## 0.16.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 6b60bd7: Replaced old config schema values from existing extensions and blueprints.
8
+
9
+ ## 0.16.0
10
+
11
+ ### Minor Changes
12
+
13
+ - fa55078: **BREAKING**: Removed the deprecated `createSchemaFromZod` helper. Use the new `configSchema` option instead. See the [1.50 migration documentation](https://backstage.io/docs/frontend-system/architecture/migrations#150) for more information.
14
+ - 49397c1: Simplified the type signature of `createRouteRef` by replacing the dual `TParams`/`TParamKeys` type parameters with a single `TParamKey` parameter. This is a breaking change for callers that explicitly provided type arguments, but most usage that relies on inference is unaffected.
15
+
16
+ ### Patch Changes
17
+
18
+ - 4c09967: Fixed the duplicate extension error message in `createFrontendModule` to correctly say "Module" instead of "Plugin".
19
+ - e4804ab: Added `open` method to `DialogApi` that renders dialogs without any built-in dialog chrome, giving the caller full control over the dialog presentation. This avoids focus trap conflicts that occur when mixing components from different design libraries. The existing `show` and `showModal` methods are now deprecated in favor of `open`.
20
+ - ddc5247: Fixed `FlattenedMessages` type to avoid excessive type instantiation depth in TypeScript 6 when using `createTranslationRef` with the `translations` option.
21
+ - a2a6c3b: Added a new `configSchema` option for `createExtension` and `createExtensionBlueprint` that accepts direct schema values from any [Standard Schema](https://github.com/standard-schema/standard-schema) compatible library with JSON Schema support, such as zod v4 or the `zod/v4` subpath from zod v3. The old `config.schema` option is now deprecated. Note that direct zod v3 schemas are not supported by the new `configSchema` option — use `import { z } from 'zod/v4'` from the zod v3 package, or upgrade to zod v4. See the [1.50 migration documentation](https://backstage.io/docs/frontend-system/architecture/migrations#150) for more information.
22
+ - d66a3ec: Added `titleLink` prop to `PageLayoutProps` so the plugin header title can link back to the plugin root.
23
+ - e220589: Removed the unnecessary need to use `defineParams` callback from `PluginHeaderActionBlueprint`. It still works, but is no longer required.
24
+ - Updated dependencies
25
+ - @backstage/errors@1.3.0
26
+ - @backstage/filter-predicates@0.1.2
27
+
3
28
  ## 0.16.0-next.2
4
29
 
5
30
  ### Patch Changes
package/dist/alpha.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { A as AnyRouteRefParams, e as ApiHolder, d as ApiRef, b as AppNode, i as AppNodeEdges, j as AppNodeInstance, k as AppNodeSpec, l as AppTree, C as ConfigurableExtensionDataRef, r as Extension, s as ExtensionAttachTo, t as ExtensionBlueprint, u as ExtensionBlueprintDefineParams, v as ExtensionBlueprintParameters, w as ExtensionBlueprintParams, x as ExtensionDataContainer, y as ExtensionDataRef, z as ExtensionDataValue, B as ExtensionDefinition, D as ExtensionDefinitionAttachTo, G as ExtensionDefinitionParameters, J as ExtensionInput, E as ExternalRouteRef, c as FrontendPlugin, M as FrontendPluginInfo, I as IconElement, O as OverridableExtensionDefinition, U as PluginWrapperApi, V as PluginWrapperBlueprint, W as PluginWrapperDefinition, X as PortableSchema, R as RouteRef, S as SubRouteRef, $ as createExtensionBlueprintParams, a7 as pluginWrapperApiRef } from './types/alpha.d-CfDtkom8.js';
1
+ export { A as AnyRouteRefParams, e as ApiHolder, d as ApiRef, b as AppNode, i as AppNodeEdges, j as AppNodeInstance, k as AppNodeSpec, l as AppTree, C as ConfigurableExtensionDataRef, r as Extension, s as ExtensionAttachTo, t as ExtensionBlueprint, u as ExtensionBlueprintDefineParams, v as ExtensionBlueprintParameters, w as ExtensionBlueprintParams, x as ExtensionDataContainer, y as ExtensionDataRef, z as ExtensionDataValue, B as ExtensionDefinition, D as ExtensionDefinitionAttachTo, G as ExtensionDefinitionParameters, J as ExtensionInput, E as ExternalRouteRef, c as FrontendPlugin, M as FrontendPluginInfo, I as IconElement, O as OverridableExtensionDefinition, U as PluginWrapperApi, V as PluginWrapperBlueprint, W as PluginWrapperDefinition, X as PortableSchema, R as RouteRef, S as SubRouteRef, $ as createExtensionBlueprintParams, a7 as pluginWrapperApiRef } from './types/alpha.d-D3gnSOzm.js';
2
+ export { StandardSchemaV1 } from '@standard-schema/spec';
2
3
  import '@backstage/frontend-plugin-api';
3
4
  import 'react';
4
5
  import '@backstage/types';
@@ -1 +1 @@
1
- {"version":3,"file":"DialogApi.esm.js","sources":["../../../src/apis/definitions/DialogApi.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n/**\n * A handle for an open dialog that can be used to interact with it.\n *\n * @remarks\n *\n * Dialogs can be opened using either {@link DialogApi.show} or {@link DialogApi.showModal}.\n *\n * @public\n */\nexport interface DialogApiDialog<TResult = void> {\n /**\n * Closes the dialog with that provided result.\n *\n * @remarks\n *\n * If the dialog is a modal dialog a result must always be provided. If it's a regular dialog then passing a result is optional.\n */\n close(\n ...args: undefined extends TResult ? [result?: TResult] : [result: TResult]\n ): void;\n\n /**\n * Replaces the content of the dialog with the provided element or component, causing it to be rerenedered.\n */\n update(\n elementOrComponent:\n | JSX.Element\n | ((props: { dialog: DialogApiDialog<TResult> }) => JSX.Element),\n ): void;\n\n /**\n * Wait until the dialog is closed and return the result.\n *\n * @remarks\n *\n * If the dialog is a modal dialog a result will always be returned. If it's a regular dialog then the result may be `undefined`.\n */\n result(): Promise<TResult>;\n}\n\n/**\n * A Utility API for showing dialogs that render in the React tree and return a result.\n *\n * @public\n */\nexport interface DialogApi {\n /**\n * Opens a modal dialog and returns a handle to it.\n *\n * @remarks\n *\n * This dialog can be closed by calling the `close` method on the returned handle, optionally providing a result.\n * The dialog can also be closed by the user by clicking the backdrop or pressing the escape key.\n *\n * If the dialog is closed without a result, the result will be `undefined`.\n *\n * @example\n *\n * ### Example with inline dialog content\n * ```tsx\n * const dialog = dialogApi.show<boolean>(\n * <DialogContent>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogActions>\n * <Button onClick={() => dialog.close(true)}>Yes</Button>\n * <Button onClick={() => dialog.close(false)}>No</Button>\n * </DialogActions>\n * </DialogContent>\n * );\n * const result = await dialog.result();\n * ```\n *\n * @example\n *\n * ### Example with separate dialog component\n * ```tsx\n * function CustomDialog({ dialog }: { dialog: DialogApiDialog<boolean | undefined> }) {\n * return (\n * <DialogContent>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogActions>\n * <Button onClick={() => dialog.close(true)}>Yes</Button>\n * <Button onClick={() => dialog.close(false)}>No</Button>\n * </DialogActions>\n * </DialogContent>\n * )\n * }\n * const result = await dialogApi.show(CustomDialog).result();\n * ```\n *\n * @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.\n * @public\n */\n show<TResult = void>(\n elementOrComponent:\n | JSX.Element\n | ((props: {\n dialog: DialogApiDialog<TResult | undefined>;\n }) => JSX.Element),\n ): DialogApiDialog<TResult | undefined>;\n\n /**\n * Opens a modal dialog and returns a handle to it.\n *\n * @remarks\n *\n * This dialog can not be closed in any other way than calling the `close` method on the returned handle and providing a result.\n *\n * @example\n *\n * ### Example with inline dialog content\n * ```tsx\n * const dialog = dialogApi.showModal<boolean>(\n * <DialogContent>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogActions>\n * <Button onClick={() => dialog.close(true)}>Yes</Button>\n * <Button onClick={() => dialog.close(false)}>No</Button>\n * </DialogActions>\n * </DialogContent>\n * );\n * const result = await dialog.result();\n * ```\n *\n * @example\n *\n * ### Example with separate dialog component\n * ```tsx\n * function CustomDialog({ dialog }: { dialog: DialogApiDialog<boolean> }) {\n * return (\n * <DialogContent>\n * <DialogTitle>Are you sure?</DialogTitle>\n * <DialogActions>\n * <Button onClick={() => dialog.close(true)}>Yes</Button>\n * <Button onClick={() => dialog.close(false)}>No</Button>\n * </DialogActions>\n * </DialogContent>\n * )\n * }\n * const result = await dialogApi.showModal(CustomDialog).result();\n * ```\n *\n * @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.\n * @public\n */\n showModal<TResult = void>(\n elementOrComponent:\n | JSX.Element\n | ((props: { dialog: DialogApiDialog<TResult> }) => JSX.Element),\n ): DialogApiDialog<TResult>;\n}\n\n/**\n * The `ApiRef` of {@link DialogApi}.\n *\n * @public\n */\nexport const dialogApiRef = createApiRef<DialogApi>().with({\n id: 'core.dialog',\n pluginId: 'app',\n});\n"],"names":[],"mappings":";;;;;AA+KO,MAAM,YAAA,GAAe,YAAA,EAAwB,CAAE,IAAA,CAAK;AAAA,EACzD,EAAA,EAAI,aAAA;AAAA,EACJ,QAAA,EAAU;AACZ,CAAC;;;;"}
1
+ {"version":3,"file":"DialogApi.esm.js","sources":["../../../src/apis/definitions/DialogApi.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createApiRef } from '../system';\n\n/**\n * A handle for an open dialog that can be used to interact with it.\n *\n * @remarks\n *\n * Dialogs are opened using {@link DialogApi.open}.\n *\n * @public\n */\nexport interface DialogApiDialog<TResult = void> {\n /**\n * Closes the dialog with the provided result.\n *\n * @remarks\n *\n * Whether a result is required depends on the `TResult` type parameter\n * chosen when the dialog was opened. If the type includes `undefined`,\n * calling `close()` without a result is allowed.\n */\n close(\n ...args: undefined extends TResult ? [result?: TResult] : [result: TResult]\n ): void;\n\n /**\n * Replaces the rendered dialog with the provided element or component.\n *\n * @remarks\n *\n * Just like the element or component passed to {@link DialogApi.open}, the\n * caller is responsible for providing the full dialog including all chrome.\n */\n update(\n elementOrComponent:\n | JSX.Element\n | ((props: { dialog: DialogApiDialog<TResult> }) => JSX.Element),\n ): void;\n\n /**\n * Wait until the dialog is closed and return the result.\n */\n result(): Promise<TResult>;\n}\n\n/**\n * A Utility API for showing dialogs that render in the React tree and return a result.\n *\n * @public\n */\nexport interface DialogApi {\n /**\n * Opens a dialog and returns a handle to it.\n *\n * @remarks\n *\n * The provided element or component is rendered as-is in the app's React tree.\n * It is the caller's responsibility to provide all dialog chrome, such as an\n * overlay, backdrop, and dialog surface. This makes the method agnostic to the\n * design library used for the dialog.\n *\n * @example\n *\n * ### Example with inline dialog element\n * ```tsx\n * const dialog = dialogApi.open<boolean>(\n * <Dialog isOpen onOpenChange={isOpen => !isOpen && dialog.close()}>\n * <DialogHeader>Are you sure?</DialogHeader>\n * <DialogBody>This action cannot be undone.</DialogBody>\n * <DialogFooter>\n * <Button onPress={() => dialog.close(false)}>Cancel</Button>\n * <Button onPress={() => dialog.close(true)}>Confirm</Button>\n * </DialogFooter>\n * </Dialog>\n * );\n * const result = await dialog.result();\n * ```\n *\n * @example\n *\n * ### Example with a dialog component\n * ```tsx\n * function ConfirmDialog({ dialog }: { dialog: DialogApiDialog<boolean> }) {\n * return (\n * <Dialog isOpen onOpenChange={isOpen => !isOpen && dialog.close()}>\n * <DialogHeader>Are you sure?</DialogHeader>\n * <DialogBody>This action cannot be undone.</DialogBody>\n * <DialogFooter>\n * <Button onPress={() => dialog.close(false)}>Cancel</Button>\n * <Button onPress={() => dialog.close(true)}>Confirm</Button>\n * </DialogFooter>\n * </Dialog>\n * );\n * }\n * const result = await dialogApi.open(ConfirmDialog).result();\n * ```\n *\n * @param elementOrComponent - The element or component to render. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.\n */\n open<TResult = void>(\n elementOrComponent:\n | JSX.Element\n | ((props: { dialog: DialogApiDialog<TResult> }) => JSX.Element),\n ): DialogApiDialog<TResult>;\n\n /**\n * Opens a dialog with built-in dialog chrome and returns a handle to it.\n *\n * @deprecated Use {@link DialogApi.open} instead. The `open` method does not\n * render any dialog chrome, giving the caller full control over the dialog\n * presentation. This avoids focus trap conflicts across design libraries.\n *\n * @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.\n */\n show<TResult = void>(\n elementOrComponent:\n | JSX.Element\n | ((props: {\n dialog: DialogApiDialog<TResult | undefined>;\n }) => JSX.Element),\n ): DialogApiDialog<TResult | undefined>;\n\n /**\n * Opens a modal dialog with built-in dialog chrome and returns a handle to it.\n *\n * @deprecated Use {@link DialogApi.open} instead. The `open` method does not\n * render any dialog chrome, giving the caller full control over the dialog\n * presentation. This avoids focus trap conflicts across design libraries.\n *\n * @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.\n */\n showModal<TResult = void>(\n elementOrComponent:\n | JSX.Element\n | ((props: { dialog: DialogApiDialog<TResult> }) => JSX.Element),\n ): DialogApiDialog<TResult>;\n}\n\n/**\n * The `ApiRef` of {@link DialogApi}.\n *\n * @public\n */\nexport const dialogApiRef = createApiRef<DialogApi>().with({\n id: 'core.dialog',\n pluginId: 'app',\n});\n"],"names":[],"mappings":";;;;;AA+JO,MAAM,YAAA,GAAe,YAAA,EAAwB,CAAE,IAAA,CAAK;AAAA,EACzD,EAAA,EAAI,aAAA;AAAA,EACJ,QAAA,EAAU;AACZ,CAAC;;;;"}
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod/v4';
1
2
  import '../wiring/coreExtensionData.esm.js';
2
3
  import 'zod/v3';
3
4
  import 'zod-to-json-schema';
@@ -23,10 +24,8 @@ const NavItemBlueprint = createExtensionBlueprint({
23
24
  routeRef
24
25
  })
25
26
  ],
26
- config: {
27
- schema: {
28
- title: (z) => z.string().optional()
29
- }
27
+ configSchema: {
28
+ title: z.string().optional()
30
29
  }
31
30
  });
32
31
 
@@ -1 +1 @@
1
- {"version":3,"file":"NavItemBlueprint.esm.js","sources":["../../src/blueprints/NavItemBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IconComponent } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { createExtensionBlueprint, createExtensionDataRef } from '../wiring';\n\n// TODO(Rugvip): Should this be broken apart into separate refs? title/icon/routeRef\nconst targetDataRef = createExtensionDataRef<{\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n}>().with({ id: 'core.nav-item.target' });\n\n/**\n * Creates extensions that make up the items of the nav bar.\n *\n * @public\n * @deprecated Nav items are now automatically inferred from `PageBlueprint`\n * extensions based on their `title` and `icon` params. You can remove your\n * `NavItemBlueprint` usage and instead pass `title` and `icon` directly to\n * the `PageBlueprint`.\n */\nexport const NavItemBlueprint = createExtensionBlueprint({\n kind: 'nav-item',\n attachTo: { id: 'app/nav', input: 'items' },\n output: [targetDataRef],\n dataRefs: {\n target: targetDataRef,\n },\n factory: (\n {\n icon,\n routeRef,\n title,\n }: {\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n },\n { config },\n ) => [\n targetDataRef({\n title: config.title ?? title,\n icon,\n routeRef,\n }),\n ],\n config: {\n schema: {\n title: z => z.string().optional(),\n },\n },\n});\n"],"names":[],"mappings":";;;;;;AAqBA,MAAM,gBAAgB,sBAAA,EAInB,CAAE,KAAK,EAAE,EAAA,EAAI,wBAAwB,CAAA;AAWjC,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,SAAA,EAAW,OAAO,OAAA,EAAQ;AAAA,EAC1C,MAAA,EAAQ,CAAC,aAAa,CAAA;AAAA,EACtB,QAAA,EAAU;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,SAAS,CACP;AAAA,IACE,IAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF,EAKA,EAAE,MAAA,EAAO,KACN;AAAA,IACH,aAAA,CAAc;AAAA,MACZ,KAAA,EAAO,OAAO,KAAA,IAAS,KAAA;AAAA,MACvB,IAAA;AAAA,MACA;AAAA,KACD;AAAA,GACH;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA;AAAS;AAClC;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"NavItemBlueprint.esm.js","sources":["../../src/blueprints/NavItemBlueprint.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z } from 'zod/v4';\nimport { IconComponent } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { createExtensionBlueprint, createExtensionDataRef } from '../wiring';\n\n// TODO(Rugvip): Should this be broken apart into separate refs? title/icon/routeRef\nconst targetDataRef = createExtensionDataRef<{\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n}>().with({ id: 'core.nav-item.target' });\n\n/**\n * Creates extensions that make up the items of the nav bar.\n *\n * @public\n * @deprecated Nav items are now automatically inferred from `PageBlueprint`\n * extensions based on their `title` and `icon` params. You can remove your\n * `NavItemBlueprint` usage and instead pass `title` and `icon` directly to\n * the `PageBlueprint`.\n */\nexport const NavItemBlueprint = createExtensionBlueprint({\n kind: 'nav-item',\n attachTo: { id: 'app/nav', input: 'items' },\n output: [targetDataRef],\n dataRefs: {\n target: targetDataRef,\n },\n factory: (\n {\n icon,\n routeRef,\n title,\n }: {\n title: string;\n icon: IconComponent;\n routeRef: RouteRef<undefined>;\n },\n { config },\n ) => [\n targetDataRef({\n title: config.title ?? title,\n icon,\n routeRef,\n }),\n ],\n configSchema: {\n title: z.string().optional(),\n },\n});\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,gBAAgB,sBAAA,EAInB,CAAE,KAAK,EAAE,EAAA,EAAI,wBAAwB,CAAA;AAWjC,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,SAAA,EAAW,OAAO,OAAA,EAAQ;AAAA,EAC1C,MAAA,EAAQ,CAAC,aAAa,CAAA;AAAA,EACtB,QAAA,EAAU;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,SAAS,CACP;AAAA,IACE,IAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF,EAKA,EAAE,MAAA,EAAO,KACN;AAAA,IACH,aAAA,CAAc;AAAA,MACZ,KAAA,EAAO,OAAO,KAAA,IAAS,KAAA;AAAA,MACvB,IAAA;AAAA,MACA;AAAA,KACD;AAAA,GACH;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS;AAE/B,CAAC;;;;"}
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { z } from 'zod/v4';
2
3
  import { Routes, Route, Navigate } from 'react-router-dom';
3
4
  import { coreExtensionData } from '../wiring/coreExtensionData.esm.js';
4
5
  import 'zod/v3';
@@ -63,11 +64,9 @@ const PageBlueprint = createExtensionBlueprint({
63
64
  coreExtensionData.title.optional(),
64
65
  coreExtensionData.icon.optional()
65
66
  ],
66
- config: {
67
- schema: {
68
- path: (z) => z.string().optional(),
69
- title: (z) => z.string().optional()
70
- }
67
+ configSchema: {
68
+ path: z.string().optional(),
69
+ title: z.string().optional()
71
70
  },
72
71
  *factory(params, { config, node, inputs }) {
73
72
  const title = config.title ?? params.title;
@@ -1 +1 @@
1
- {"version":3,"file":"PageBlueprint.esm.js","sources":["../../src/blueprints/PageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JSX } from 'react';\nimport { Routes, Route, Navigate } from 'react-router-dom';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionInput,\n} from '../wiring';\nimport { ExtensionBoundary, PageLayout, PageLayoutTab } from '../components';\nimport { useApi } from '../apis/system';\nimport { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi';\nimport { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';\nimport { RouteResolutionApi } from '../apis/definitions/RouteResolutionApi';\n\nfunction resolveTitleLink(\n routeResolutionApi: RouteResolutionApi,\n routeRef: RouteRef | undefined,\n): string | undefined {\n if (!routeRef) {\n return undefined;\n }\n try {\n return routeResolutionApi.resolve(routeRef)?.();\n } catch {\n // Route ref may require params not available in the current context\n return undefined;\n }\n}\n\n/**\n * Creates extensions that are routable React page components.\n *\n * @public\n */\nexport const PageBlueprint = createExtensionBlueprint({\n kind: 'page',\n attachTo: { id: 'app/routes', input: 'routes' },\n inputs: {\n pages: createExtensionInput([\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.reactElement,\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ],\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n },\n },\n *factory(\n params: {\n path: string;\n title?: string;\n icon?: IconElement;\n loader?: () => Promise<JSX.Element>;\n routeRef?: RouteRef;\n /**\n * Hide the default plugin page header, making the page fill up all available space.\n */\n noHeader?: boolean;\n },\n { config, node, inputs },\n ) {\n const title = config.title ?? params.title;\n const icon = params.icon;\n const pluginId = node.spec.plugin.pluginId;\n const noHeader = params.noHeader ?? false;\n const resolvedTitle =\n title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;\n const resolvedIcon = icon ?? node.spec.plugin.icon;\n const titleRouteRef =\n (node.spec.plugin.routes as { root?: RouteRef }).root ?? params.routeRef;\n\n yield coreExtensionData.routePath(config.path ?? params.path);\n if (params.loader) {\n const loader = params.loader;\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n noHeader={noHeader}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n {ExtensionBoundary.lazy(node, loader)}\n </PageLayout>\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n } else if (inputs.pages.length > 0) {\n // Parent page with sub-pages - render header with tabs\n const tabs: PageLayoutTab[] = inputs.pages.map(page => {\n const path = page.get(coreExtensionData.routePath);\n const tabTitle = page.get(coreExtensionData.title);\n const tabIcon = page.get(coreExtensionData.icon);\n return {\n id: path,\n label: tabTitle || path,\n icon: tabIcon,\n href: path,\n };\n });\n\n const PageContent = () => {\n const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n tabs={tabs}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n <Routes>\n {firstPagePath && (\n <Route\n index\n element={<Navigate to={firstPagePath} replace />}\n />\n )}\n {inputs.pages.map((page, index) => {\n const path = page.get(coreExtensionData.routePath);\n const element = page.get(coreExtensionData.reactElement);\n return (\n <Route key={index} path={`${path}/*`} element={element} />\n );\n })}\n </Routes>\n </PageLayout>\n );\n };\n\n yield coreExtensionData.reactElement(<PageContent />);\n } else {\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n titleLink={titleLink}\n headerActions={headerActions}\n />\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n }\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (title) {\n yield coreExtensionData.title(title);\n }\n if (icon) {\n yield coreExtensionData.icon(icon);\n }\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAS,gBAAA,CACP,oBACA,QAAA,EACoB;AACpB,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,IAAI;AACF,IAAA,OAAO,kBAAA,CAAmB,OAAA,CAAQ,QAAQ,CAAA,IAAI;AAAA,EAChD,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAOO,MAAM,gBAAgB,wBAAA,CAAyB;AAAA,EACpD,IAAA,EAAM,MAAA;AAAA,EACN,QAAA,EAAU,EAAE,EAAA,EAAI,YAAA,EAAc,OAAO,QAAA,EAAS;AAAA,EAC9C,MAAA,EAAQ;AAAA,IACN,OAAO,oBAAA,CAAqB;AAAA,MAC1B,iBAAA,CAAkB,SAAA;AAAA,MAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,MACpC,iBAAA,CAAkB,YAAA;AAAA,MAClB,iBAAA,CAAkB,MAAM,QAAA,EAAS;AAAA,MACjC,iBAAA,CAAkB,KAAK,QAAA;AAAS,KACjC;AAAA,GACH;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,iBAAA,CAAkB,SAAA;AAAA,IAClB,iBAAA,CAAkB,YAAA;AAAA,IAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,IACpC,iBAAA,CAAkB,MAAM,QAAA,EAAS;AAAA,IACjC,iBAAA,CAAkB,KAAK,QAAA;AAAS,GAClC;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,IAAA,EAAM,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA,EAAS;AAAA,MAC/B,KAAA,EAAO,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA;AAAS;AAClC,GACF;AAAA,EACA,CAAC,OAAA,CACC,MAAA,EAWA,EAAE,MAAA,EAAQ,IAAA,EAAM,QAAO,EACvB;AACA,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,IAAS,MAAA,CAAO,KAAA;AACrC,IAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AACpB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,QAAA;AAClC,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,KAAA;AACpC,IAAA,MAAM,aAAA,GACJ,SAAS,IAAA,CAAK,IAAA,CAAK,OAAO,KAAA,IAAS,IAAA,CAAK,KAAK,MAAA,CAAO,QAAA;AACtD,IAAA,MAAM,YAAA,GAAe,IAAA,IAAQ,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,IAAA;AAC9C,IAAA,MAAM,gBACH,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,MAAA,CAA+B,QAAQ,MAAA,CAAO,QAAA;AAElE,IAAA,MAAM,iBAAA,CAAkB,SAAA,CAAU,MAAA,CAAO,IAAA,IAAQ,OAAO,IAAI,CAAA;AAC5D,IAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,MAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,MAAA,MAAM,cAAc,MAAM;AACxB,QAAA,MAAM,kBAAA,GAAqB,OAAO,qBAAqB,CAAA;AACvD,QAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,kBAAA,EAAoB,aAAa,CAAA;AACpE,QAAA,MAAM,gBAAA,GAAmB,OAAO,yBAAyB,CAAA;AACzD,QAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,sBAAA,CAAuB,QAAQ,CAAA;AAEtE,QAAA,uBACE,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO,aAAA;AAAA,YACP,IAAA,EAAM,YAAA;AAAA,YACN,QAAA;AAAA,YACA,SAAA;AAAA,YACA,aAAA;AAAA,YAEC,QAAA,EAAA,iBAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,MAAM;AAAA;AAAA,SACtC;AAAA,MAEJ,CAAA;AACA,MAAA,MAAM,iBAAA,CAAkB,YAAA,iBAAa,GAAA,CAAC,WAAA,EAAA,EAAY,CAAE,CAAA;AAAA,IACtD,CAAA,MAAA,IAAW,MAAA,CAAO,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAElC,MAAA,MAAM,IAAA,GAAwB,MAAA,CAAO,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AACrD,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,iBAAA,CAAkB,SAAS,CAAA;AACjD,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,iBAAA,CAAkB,KAAK,CAAA;AACjD,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,iBAAA,CAAkB,IAAI,CAAA;AAC/C,QAAA,OAAO;AAAA,UACL,EAAA,EAAI,IAAA;AAAA,UACJ,OAAO,QAAA,IAAY,IAAA;AAAA,UACnB,IAAA,EAAM,OAAA;AAAA,UACN,IAAA,EAAM;AAAA,SACR;AAAA,MACF,CAAC,CAAA;AAED,MAAA,MAAM,cAAc,MAAM;AACxB,QAAA,MAAM,gBAAgB,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,EAAG,GAAA,CAAI,kBAAkB,SAAS,CAAA;AACtE,QAAA,MAAM,kBAAA,GAAqB,OAAO,qBAAqB,CAAA;AACvD,QAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,kBAAA,EAAoB,aAAa,CAAA;AAEpE,QAAA,MAAM,gBAAA,GAAmB,OAAO,yBAAyB,CAAA;AACzD,QAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,sBAAA,CAAuB,QAAQ,CAAA;AAEtE,QAAA,uBACE,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO,aAAA;AAAA,YACP,IAAA,EAAM,YAAA;AAAA,YACN,IAAA;AAAA,YACA,SAAA;AAAA,YACA,aAAA;AAAA,YAEA,+BAAC,MAAA,EAAA,EACE,QAAA,EAAA;AAAA,cAAA,aAAA,oBACC,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,KAAA,EAAK,IAAA;AAAA,kBACL,yBAAS,GAAA,CAAC,QAAA,EAAA,EAAS,EAAA,EAAI,aAAA,EAAe,SAAO,IAAA,EAAC;AAAA;AAAA,eAChD;AAAA,cAED,MAAA,CAAO,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,KAAA,KAAU;AACjC,gBAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,iBAAA,CAAkB,SAAS,CAAA;AACjD,gBAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,iBAAA,CAAkB,YAAY,CAAA;AACvD,gBAAA,2BACG,KAAA,EAAA,EAAkB,IAAA,EAAM,GAAG,IAAI,CAAA,EAAA,CAAA,EAAM,WAA1B,KAA4C,CAAA;AAAA,cAE5D,CAAC;AAAA,aAAA,EACH;AAAA;AAAA,SACF;AAAA,MAEJ,CAAA;AAEA,MAAA,MAAM,iBAAA,CAAkB,YAAA,iBAAa,GAAA,CAAC,WAAA,EAAA,EAAY,CAAE,CAAA;AAAA,IACtD,CAAA,MAAO;AACL,MAAA,MAAM,cAAc,MAAM;AACxB,QAAA,MAAM,kBAAA,GAAqB,OAAO,qBAAqB,CAAA;AACvD,QAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,kBAAA,EAAoB,aAAa,CAAA;AACpE,QAAA,MAAM,gBAAA,GAAmB,OAAO,yBAAyB,CAAA;AACzD,QAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,sBAAA,CAAuB,QAAQ,CAAA;AACtE,QAAA,uBACE,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO,aAAA;AAAA,YACP,IAAA,EAAM,YAAA;AAAA,YACN,SAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,MAEJ,CAAA;AACA,MAAA,MAAM,iBAAA,CAAkB,YAAA,iBAAa,GAAA,CAAC,WAAA,EAAA,EAAY,CAAE,CAAA;AAAA,IACtD;AACA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAM,iBAAA,CAAkB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA;AAAA,IAClD;AACA,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAM,iBAAA,CAAkB,MAAM,KAAK,CAAA;AAAA,IACrC;AACA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,iBAAA,CAAkB,KAAK,IAAI,CAAA;AAAA,IACnC;AAAA,EACF;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"PageBlueprint.esm.js","sources":["../../src/blueprints/PageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z } from 'zod/v4';\nimport { JSX } from 'react';\nimport { Routes, Route, Navigate } from 'react-router-dom';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionInput,\n} from '../wiring';\nimport { ExtensionBoundary, PageLayout, PageLayoutTab } from '../components';\nimport { useApi } from '../apis/system';\nimport { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi';\nimport { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';\nimport { RouteResolutionApi } from '../apis/definitions/RouteResolutionApi';\n\nfunction resolveTitleLink(\n routeResolutionApi: RouteResolutionApi,\n routeRef: RouteRef | undefined,\n): string | undefined {\n if (!routeRef) {\n return undefined;\n }\n try {\n return routeResolutionApi.resolve(routeRef)?.();\n } catch {\n // Route ref may require params not available in the current context\n return undefined;\n }\n}\n\n/**\n * Creates extensions that are routable React page components.\n *\n * @public\n */\nexport const PageBlueprint = createExtensionBlueprint({\n kind: 'page',\n attachTo: { id: 'app/routes', input: 'routes' },\n inputs: {\n pages: createExtensionInput([\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.reactElement,\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ],\n configSchema: {\n path: z.string().optional(),\n title: z.string().optional(),\n },\n *factory(\n params: {\n path: string;\n title?: string;\n icon?: IconElement;\n loader?: () => Promise<JSX.Element>;\n routeRef?: RouteRef;\n /**\n * Hide the default plugin page header, making the page fill up all available space.\n */\n noHeader?: boolean;\n },\n { config, node, inputs },\n ) {\n const title = config.title ?? params.title;\n const icon = params.icon;\n const pluginId = node.spec.plugin.pluginId;\n const noHeader = params.noHeader ?? false;\n const resolvedTitle =\n title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;\n const resolvedIcon = icon ?? node.spec.plugin.icon;\n const titleRouteRef =\n (node.spec.plugin.routes as { root?: RouteRef }).root ?? params.routeRef;\n\n yield coreExtensionData.routePath(config.path ?? params.path);\n if (params.loader) {\n const loader = params.loader;\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n noHeader={noHeader}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n {ExtensionBoundary.lazy(node, loader)}\n </PageLayout>\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n } else if (inputs.pages.length > 0) {\n // Parent page with sub-pages - render header with tabs\n const tabs: PageLayoutTab[] = inputs.pages.map(page => {\n const path = page.get(coreExtensionData.routePath);\n const tabTitle = page.get(coreExtensionData.title);\n const tabIcon = page.get(coreExtensionData.icon);\n return {\n id: path,\n label: tabTitle || path,\n icon: tabIcon,\n href: path,\n };\n });\n\n const PageContent = () => {\n const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n tabs={tabs}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n <Routes>\n {firstPagePath && (\n <Route\n index\n element={<Navigate to={firstPagePath} replace />}\n />\n )}\n {inputs.pages.map((page, index) => {\n const path = page.get(coreExtensionData.routePath);\n const element = page.get(coreExtensionData.reactElement);\n return (\n <Route key={index} path={`${path}/*`} element={element} />\n );\n })}\n </Routes>\n </PageLayout>\n );\n };\n\n yield coreExtensionData.reactElement(<PageContent />);\n } else {\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n titleLink={titleLink}\n headerActions={headerActions}\n />\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n }\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (title) {\n yield coreExtensionData.title(title);\n }\n if (icon) {\n yield coreExtensionData.icon(icon);\n }\n },\n});\n"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { z } from 'zod/v4';
1
2
  import { coreExtensionData } from '../wiring/coreExtensionData.esm.js';
2
3
  import 'zod/v3';
3
4
  import 'zod-to-json-schema';
@@ -43,11 +44,9 @@ const SubPageBlueprint = createExtensionBlueprint({
43
44
  coreExtensionData.routeRef.optional(),
44
45
  coreExtensionData.icon.optional()
45
46
  ],
46
- config: {
47
- schema: {
48
- path: (z) => z.string().optional(),
49
- title: (z) => z.string().optional()
50
- }
47
+ configSchema: {
48
+ path: z.string().optional(),
49
+ title: z.string().optional()
51
50
  },
52
51
  *factory(params, { config, node }) {
53
52
  yield coreExtensionData.routePath(config.path ?? params.path);
@@ -1 +1 @@
1
- {"version":3,"file":"SubPageBlueprint.esm.js","sources":["../../src/blueprints/SubPageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { coreExtensionData, createExtensionBlueprint } from '../wiring';\nimport { ExtensionBoundary } from '../components';\n\n/**\n * Creates extensions that are sub-page React components attached to a parent page.\n * Sub-pages are rendered as tabs within the parent page's header.\n *\n * @public\n * @example\n * ```tsx\n * const overviewRouteRef = createRouteRef();\n *\n * const mySubPage = SubPageBlueprint.make({\n * attachTo: { id: 'page:my-plugin', input: 'pages' },\n * name: 'overview',\n * params: {\n * path: 'overview',\n * title: 'Overview',\n * routeRef: overviewRouteRef,\n * loader: () => import('./components/Overview').then(m => <m.Overview />),\n * },\n * });\n * ```\n */\nexport const SubPageBlueprint = createExtensionBlueprint({\n kind: 'sub-page',\n attachTo: { relative: { kind: 'page' }, input: 'pages' },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.title,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.icon.optional(),\n ],\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n },\n },\n *factory(\n params: {\n /**\n * The path for this sub-page, relative to the parent page. Must **not** start with '/'.\n *\n * @example 'overview', 'settings', 'details'\n */\n path: string;\n /**\n * The title displayed in the tab for this sub-page.\n */\n title: string;\n /**\n * Optional icon for this sub-page, displayed in the tab.\n */\n icon?: IconElement;\n /**\n * A function that returns a promise resolving to the React element to render.\n * This enables lazy loading of the sub-page content.\n */\n loader: () => Promise<JSX.Element>;\n /**\n * Optional route reference for this sub-page.\n */\n routeRef?: RouteRef;\n },\n { config, node },\n ) {\n yield coreExtensionData.routePath(config.path ?? params.path);\n yield coreExtensionData.title(config.title ?? params.title);\n yield coreExtensionData.reactElement(\n ExtensionBoundary.lazy(node, params.loader),\n );\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (params.icon) {\n yield coreExtensionData.icon(params.icon);\n }\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CO,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,QAAA,EAAU,EAAE,MAAM,MAAA,EAAO,EAAG,OAAO,OAAA,EAAQ;AAAA,EACvD,MAAA,EAAQ;AAAA,IACN,iBAAA,CAAkB,SAAA;AAAA,IAClB,iBAAA,CAAkB,YAAA;AAAA,IAClB,iBAAA,CAAkB,KAAA;AAAA,IAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,IACpC,iBAAA,CAAkB,KAAK,QAAA;AAAS,GAClC;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ;AAAA,MACN,IAAA,EAAM,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA,EAAS;AAAA,MAC/B,KAAA,EAAO,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,GAAS,QAAA;AAAS;AAClC,GACF;AAAA,EACA,CAAC,OAAA,CACC,MAAA,EAyBA,EAAE,MAAA,EAAQ,MAAK,EACf;AACA,IAAA,MAAM,iBAAA,CAAkB,SAAA,CAAU,MAAA,CAAO,IAAA,IAAQ,OAAO,IAAI,CAAA;AAC5D,IAAA,MAAM,iBAAA,CAAkB,KAAA,CAAM,MAAA,CAAO,KAAA,IAAS,OAAO,KAAK,CAAA;AAC1D,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,MACtB,iBAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,MAAA,CAAO,MAAM;AAAA,KAC5C;AACA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAM,iBAAA,CAAkB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA;AAAA,IAClD;AACA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAM,iBAAA,CAAkB,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA;AAAA,IAC1C;AAAA,EACF;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"SubPageBlueprint.esm.js","sources":["../../src/blueprints/SubPageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z } from 'zod/v4';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport { coreExtensionData, createExtensionBlueprint } from '../wiring';\nimport { ExtensionBoundary } from '../components';\n\n/**\n * Creates extensions that are sub-page React components attached to a parent page.\n * Sub-pages are rendered as tabs within the parent page's header.\n *\n * @public\n * @example\n * ```tsx\n * const overviewRouteRef = createRouteRef();\n *\n * const mySubPage = SubPageBlueprint.make({\n * attachTo: { id: 'page:my-plugin', input: 'pages' },\n * name: 'overview',\n * params: {\n * path: 'overview',\n * title: 'Overview',\n * routeRef: overviewRouteRef,\n * loader: () => import('./components/Overview').then(m => <m.Overview />),\n * },\n * });\n * ```\n */\nexport const SubPageBlueprint = createExtensionBlueprint({\n kind: 'sub-page',\n attachTo: { relative: { kind: 'page' }, input: 'pages' },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.title,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.icon.optional(),\n ],\n configSchema: {\n path: z.string().optional(),\n title: z.string().optional(),\n },\n *factory(\n params: {\n /**\n * The path for this sub-page, relative to the parent page. Must **not** start with '/'.\n *\n * @example 'overview', 'settings', 'details'\n */\n path: string;\n /**\n * The title displayed in the tab for this sub-page.\n */\n title: string;\n /**\n * Optional icon for this sub-page, displayed in the tab.\n */\n icon?: IconElement;\n /**\n * A function that returns a promise resolving to the React element to render.\n * This enables lazy loading of the sub-page content.\n */\n loader: () => Promise<JSX.Element>;\n /**\n * Optional route reference for this sub-page.\n */\n routeRef?: RouteRef;\n },\n { config, node },\n ) {\n yield coreExtensionData.routePath(config.path ?? params.path);\n yield coreExtensionData.title(config.title ?? params.title);\n yield coreExtensionData.reactElement(\n ExtensionBoundary.lazy(node, params.loader),\n );\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (params.icon) {\n yield coreExtensionData.icon(params.icon);\n }\n },\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CO,MAAM,mBAAmB,wBAAA,CAAyB;AAAA,EACvD,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,EAAE,QAAA,EAAU,EAAE,MAAM,MAAA,EAAO,EAAG,OAAO,OAAA,EAAQ;AAAA,EACvD,MAAA,EAAQ;AAAA,IACN,iBAAA,CAAkB,SAAA;AAAA,IAClB,iBAAA,CAAkB,YAAA;AAAA,IAClB,iBAAA,CAAkB,KAAA;AAAA,IAClB,iBAAA,CAAkB,SAAS,QAAA,EAAS;AAAA,IACpC,iBAAA,CAAkB,KAAK,QAAA;AAAS,GAClC;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC1B,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC7B;AAAA,EACA,CAAC,OAAA,CACC,MAAA,EAyBA,EAAE,MAAA,EAAQ,MAAK,EACf;AACA,IAAA,MAAM,iBAAA,CAAkB,SAAA,CAAU,MAAA,CAAO,IAAA,IAAQ,OAAO,IAAI,CAAA;AAC5D,IAAA,MAAM,iBAAA,CAAkB,KAAA,CAAM,MAAA,CAAO,KAAA,IAAS,OAAO,KAAK,CAAA;AAC1D,IAAA,MAAM,iBAAA,CAAkB,YAAA;AAAA,MACtB,iBAAA,CAAkB,IAAA,CAAK,IAAA,EAAM,MAAA,CAAO,MAAM;AAAA,KAC5C;AACA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAM,iBAAA,CAAkB,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAA;AAAA,IAClD;AACA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAM,iBAAA,CAAkB,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA;AAAA,IAC1C;AAAA,EACF;AACF,CAAC;;;;"}
package/dist/index.d.ts CHANGED
@@ -2,10 +2,11 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, JSX as JSX$1, ComponentType, PropsWithChildren } from 'react';
4
4
  import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
5
- import { I as IconElement, R as RouteRef, A as AnyRouteRefParams, S as SubRouteRef, E as ExternalRouteRef, F as FrontendFeature, a as IconComponent, b as AppNode, c as FrontendPlugin, d as ApiRef, e as ApiHolder, T as TypesToApiRefs, f as ApiFactory, g as AnyApiFactory } from './types/alpha.d-CfDtkom8.js';
6
- export { h as AnyApiRef, i as AppNodeEdges, j as AppNodeInstance, k as AppNodeSpec, l as AppTree, m as AppTreeApi, C as ConfigurableExtensionDataRef, n as CreateExtensionBlueprintOptions, o as CreateExtensionOptions, p as CreateFrontendModuleOptions, q as CreateFrontendPluginOptions, r as Extension, s as ExtensionAttachTo, t as ExtensionBlueprint, u as ExtensionBlueprintDefineParams, v as ExtensionBlueprintParameters, w as ExtensionBlueprintParams, x as ExtensionDataContainer, y as ExtensionDataRef, z as ExtensionDataValue, B as ExtensionDefinition, D as ExtensionDefinitionAttachTo, G as ExtensionDefinitionParameters, H as ExtensionFactoryMiddleware, J as ExtensionInput, K as FeatureFlagConfig, L as FrontendModule, M as FrontendPluginInfo, N as FrontendPluginInfoOptions, O as OverridableExtensionDefinition, P as OverridableFrontendPlugin, Q as PluginOptions, U as PluginWrapperApi, V as PluginWrapperBlueprint, W as PluginWrapperDefinition, X as PortableSchema, Y as appTreeApiRef, Z as createExtension, _ as createExtensionBlueprint, $ as createExtensionBlueprintParams, a0 as createExtensionDataRef, a1 as createExtensionInput, a2 as createExternalRouteRef, a3 as createFrontendModule, a4 as createFrontendPlugin, a5 as createRouteRef, a6 as createSubRouteRef, a7 as pluginWrapperApiRef } from './types/alpha.d-CfDtkom8.js';
5
+ import { I as IconElement, R as RouteRef, A as AnyRouteRefParams, S as SubRouteRef, E as ExternalRouteRef, F as FrontendFeature, a as IconComponent, b as AppNode, c as FrontendPlugin, d as ApiRef, e as ApiHolder, T as TypesToApiRefs, f as ApiFactory, g as AnyApiFactory } from './types/alpha.d-D3gnSOzm.js';
6
+ export { h as AnyApiRef, i as AppNodeEdges, j as AppNodeInstance, k as AppNodeSpec, l as AppTree, m as AppTreeApi, C as ConfigurableExtensionDataRef, n as CreateExtensionBlueprintOptions, o as CreateExtensionOptions, p as CreateFrontendModuleOptions, q as CreateFrontendPluginOptions, r as Extension, s as ExtensionAttachTo, t as ExtensionBlueprint, u as ExtensionBlueprintDefineParams, v as ExtensionBlueprintParameters, w as ExtensionBlueprintParams, x as ExtensionDataContainer, y as ExtensionDataRef, z as ExtensionDataValue, B as ExtensionDefinition, D as ExtensionDefinitionAttachTo, G as ExtensionDefinitionParameters, H as ExtensionFactoryMiddleware, J as ExtensionInput, K as FeatureFlagConfig, L as FrontendModule, M as FrontendPluginInfo, N as FrontendPluginInfoOptions, O as OverridableExtensionDefinition, P as OverridableFrontendPlugin, Q as PluginOptions, U as PluginWrapperApi, V as PluginWrapperBlueprint, W as PluginWrapperDefinition, X as PortableSchema, Y as appTreeApiRef, Z as createExtension, _ as createExtensionBlueprint, $ as createExtensionBlueprintParams, a0 as createExtensionDataRef, a1 as createExtensionInput, a2 as createExternalRouteRef, a3 as createFrontendModule, a4 as createFrontendPlugin, a5 as createRouteRef, a6 as createSubRouteRef, a7 as pluginWrapperApiRef } from './types/alpha.d-D3gnSOzm.js';
7
7
  import { Observable, JsonValue, Expand, ExpandRecursive } from '@backstage/types';
8
8
  import { Config } from '@backstage/config';
9
+ export { StandardSchemaV1 } from '@standard-schema/spec';
9
10
  import '@backstage/filter-predicates';
10
11
  import 'zod/v3';
11
12
 
@@ -1106,31 +1107,34 @@ declare const identityApiRef: _backstage_frontend_plugin_api.ApiRef<IdentityApi,
1106
1107
  *
1107
1108
  * @remarks
1108
1109
  *
1109
- * Dialogs can be opened using either {@link DialogApi.show} or {@link DialogApi.showModal}.
1110
+ * Dialogs are opened using {@link DialogApi.open}.
1110
1111
  *
1111
1112
  * @public
1112
1113
  */
1113
1114
  interface DialogApiDialog<TResult = void> {
1114
1115
  /**
1115
- * Closes the dialog with that provided result.
1116
+ * Closes the dialog with the provided result.
1116
1117
  *
1117
1118
  * @remarks
1118
1119
  *
1119
- * If the dialog is a modal dialog a result must always be provided. If it's a regular dialog then passing a result is optional.
1120
+ * Whether a result is required depends on the `TResult` type parameter
1121
+ * chosen when the dialog was opened. If the type includes `undefined`,
1122
+ * calling `close()` without a result is allowed.
1120
1123
  */
1121
1124
  close(...args: undefined extends TResult ? [result?: TResult] : [result: TResult]): void;
1122
1125
  /**
1123
- * Replaces the content of the dialog with the provided element or component, causing it to be rerenedered.
1126
+ * Replaces the rendered dialog with the provided element or component.
1127
+ *
1128
+ * @remarks
1129
+ *
1130
+ * Just like the element or component passed to {@link DialogApi.open}, the
1131
+ * caller is responsible for providing the full dialog including all chrome.
1124
1132
  */
1125
1133
  update(elementOrComponent: JSX.Element | ((props: {
1126
1134
  dialog: DialogApiDialog<TResult>;
1127
1135
  }) => JSX.Element)): void;
1128
1136
  /**
1129
1137
  * Wait until the dialog is closed and return the result.
1130
- *
1131
- * @remarks
1132
- *
1133
- * If the dialog is a modal dialog a result will always be returned. If it's a regular dialog then the result may be `undefined`.
1134
1138
  */
1135
1139
  result(): Promise<TResult>;
1136
1140
  }
@@ -1141,98 +1145,76 @@ interface DialogApiDialog<TResult = void> {
1141
1145
  */
1142
1146
  interface DialogApi {
1143
1147
  /**
1144
- * Opens a modal dialog and returns a handle to it.
1148
+ * Opens a dialog and returns a handle to it.
1145
1149
  *
1146
1150
  * @remarks
1147
1151
  *
1148
- * This dialog can be closed by calling the `close` method on the returned handle, optionally providing a result.
1149
- * The dialog can also be closed by the user by clicking the backdrop or pressing the escape key.
1150
- *
1151
- * If the dialog is closed without a result, the result will be `undefined`.
1152
+ * The provided element or component is rendered as-is in the app's React tree.
1153
+ * It is the caller's responsibility to provide all dialog chrome, such as an
1154
+ * overlay, backdrop, and dialog surface. This makes the method agnostic to the
1155
+ * design library used for the dialog.
1152
1156
  *
1153
1157
  * @example
1154
1158
  *
1155
- * ### Example with inline dialog content
1159
+ * ### Example with inline dialog element
1156
1160
  * ```tsx
1157
- * const dialog = dialogApi.show<boolean>(
1158
- * <DialogContent>
1159
- * <DialogTitle>Are you sure?</DialogTitle>
1160
- * <DialogActions>
1161
- * <Button onClick={() => dialog.close(true)}>Yes</Button>
1162
- * <Button onClick={() => dialog.close(false)}>No</Button>
1163
- * </DialogActions>
1164
- * </DialogContent>
1161
+ * const dialog = dialogApi.open<boolean>(
1162
+ * <Dialog isOpen onOpenChange={isOpen => !isOpen && dialog.close()}>
1163
+ * <DialogHeader>Are you sure?</DialogHeader>
1164
+ * <DialogBody>This action cannot be undone.</DialogBody>
1165
+ * <DialogFooter>
1166
+ * <Button onPress={() => dialog.close(false)}>Cancel</Button>
1167
+ * <Button onPress={() => dialog.close(true)}>Confirm</Button>
1168
+ * </DialogFooter>
1169
+ * </Dialog>
1165
1170
  * );
1166
1171
  * const result = await dialog.result();
1167
1172
  * ```
1168
1173
  *
1169
1174
  * @example
1170
1175
  *
1171
- * ### Example with separate dialog component
1176
+ * ### Example with a dialog component
1172
1177
  * ```tsx
1173
- * function CustomDialog({ dialog }: { dialog: DialogApiDialog<boolean | undefined> }) {
1178
+ * function ConfirmDialog({ dialog }: { dialog: DialogApiDialog<boolean> }) {
1174
1179
  * return (
1175
- * <DialogContent>
1176
- * <DialogTitle>Are you sure?</DialogTitle>
1177
- * <DialogActions>
1178
- * <Button onClick={() => dialog.close(true)}>Yes</Button>
1179
- * <Button onClick={() => dialog.close(false)}>No</Button>
1180
- * </DialogActions>
1181
- * </DialogContent>
1182
- * )
1180
+ * <Dialog isOpen onOpenChange={isOpen => !isOpen && dialog.close()}>
1181
+ * <DialogHeader>Are you sure?</DialogHeader>
1182
+ * <DialogBody>This action cannot be undone.</DialogBody>
1183
+ * <DialogFooter>
1184
+ * <Button onPress={() => dialog.close(false)}>Cancel</Button>
1185
+ * <Button onPress={() => dialog.close(true)}>Confirm</Button>
1186
+ * </DialogFooter>
1187
+ * </Dialog>
1188
+ * );
1183
1189
  * }
1184
- * const result = await dialogApi.show(CustomDialog).result();
1190
+ * const result = await dialogApi.open(ConfirmDialog).result();
1185
1191
  * ```
1186
1192
  *
1193
+ * @param elementOrComponent - The element or component to render. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.
1194
+ */
1195
+ open<TResult = void>(elementOrComponent: JSX.Element | ((props: {
1196
+ dialog: DialogApiDialog<TResult>;
1197
+ }) => JSX.Element)): DialogApiDialog<TResult>;
1198
+ /**
1199
+ * Opens a dialog with built-in dialog chrome and returns a handle to it.
1200
+ *
1201
+ * @deprecated Use {@link DialogApi.open} instead. The `open` method does not
1202
+ * render any dialog chrome, giving the caller full control over the dialog
1203
+ * presentation. This avoids focus trap conflicts across design libraries.
1204
+ *
1187
1205
  * @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.
1188
- * @public
1189
1206
  */
1190
1207
  show<TResult = void>(elementOrComponent: JSX.Element | ((props: {
1191
1208
  dialog: DialogApiDialog<TResult | undefined>;
1192
1209
  }) => JSX.Element)): DialogApiDialog<TResult | undefined>;
1193
1210
  /**
1194
- * Opens a modal dialog and returns a handle to it.
1195
- *
1196
- * @remarks
1197
- *
1198
- * This dialog can not be closed in any other way than calling the `close` method on the returned handle and providing a result.
1211
+ * Opens a modal dialog with built-in dialog chrome and returns a handle to it.
1199
1212
  *
1200
- * @example
1201
- *
1202
- * ### Example with inline dialog content
1203
- * ```tsx
1204
- * const dialog = dialogApi.showModal<boolean>(
1205
- * <DialogContent>
1206
- * <DialogTitle>Are you sure?</DialogTitle>
1207
- * <DialogActions>
1208
- * <Button onClick={() => dialog.close(true)}>Yes</Button>
1209
- * <Button onClick={() => dialog.close(false)}>No</Button>
1210
- * </DialogActions>
1211
- * </DialogContent>
1212
- * );
1213
- * const result = await dialog.result();
1214
- * ```
1215
- *
1216
- * @example
1217
- *
1218
- * ### Example with separate dialog component
1219
- * ```tsx
1220
- * function CustomDialog({ dialog }: { dialog: DialogApiDialog<boolean> }) {
1221
- * return (
1222
- * <DialogContent>
1223
- * <DialogTitle>Are you sure?</DialogTitle>
1224
- * <DialogActions>
1225
- * <Button onClick={() => dialog.close(true)}>Yes</Button>
1226
- * <Button onClick={() => dialog.close(false)}>No</Button>
1227
- * </DialogActions>
1228
- * </DialogContent>
1229
- * )
1230
- * }
1231
- * const result = await dialogApi.showModal(CustomDialog).result();
1232
- * ```
1213
+ * @deprecated Use {@link DialogApi.open} instead. The `open` method does not
1214
+ * render any dialog chrome, giving the caller full control over the dialog
1215
+ * presentation. This avoids focus trap conflicts across design libraries.
1233
1216
  *
1234
1217
  * @param elementOrComponent - The element or component to render in the dialog. If a component is provided, it will be provided with a `dialog` prop that contains the dialog handle.
1235
- * @public
1236
1218
  */
1237
1219
  showModal<TResult = void>(elementOrComponent: JSX.Element | ((props: {
1238
1220
  dialog: DialogApiDialog<TResult>;
@@ -2286,8 +2268,12 @@ declare const NavItemBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprin
2286
2268
  routeRef: RouteRef<undefined>;
2287
2269
  }, "core.nav-item.target", {}>;
2288
2270
  inputs: {};
2289
- config: {};
2290
- configInput: {};
2271
+ config: {
2272
+ title: string | undefined;
2273
+ };
2274
+ configInput: {
2275
+ title?: string | undefined;
2276
+ };
2291
2277
  dataRefs: {
2292
2278
  target: _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<{
2293
2279
  title: string;
@@ -2340,8 +2326,8 @@ declare const PageBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprint<{
2340
2326
  title: string | undefined;
2341
2327
  };
2342
2328
  configInput: {
2343
- title?: string | undefined;
2344
2329
  path?: string | undefined;
2330
+ title?: string | undefined;
2345
2331
  };
2346
2332
  dataRefs: never;
2347
2333
  }>;
@@ -2405,8 +2391,8 @@ declare const SubPageBlueprint: _backstage_frontend_plugin_api.ExtensionBlueprin
2405
2391
  title: string | undefined;
2406
2392
  };
2407
2393
  configInput: {
2408
- title?: string | undefined;
2409
2394
  path?: string | undefined;
2395
+ title?: string | undefined;
2410
2396
  };
2411
2397
  dataRefs: never;
2412
2398
  }>;