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

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,24 @@
1
1
  # @backstage/frontend-plugin-api
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 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.
8
+ - 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.
9
+
10
+ ### Patch Changes
11
+
12
+ - 4c09967: Fixed the duplicate extension error message in `createFrontendModule` to correctly say "Module" instead of "Plugin".
13
+ - 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`.
14
+ - ddc5247: Fixed `FlattenedMessages` type to avoid excessive type instantiation depth in TypeScript 6 when using `createTranslationRef` with the `translations` option.
15
+ - 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.
16
+ - d66a3ec: Added `titleLink` prop to `PageLayoutProps` so the plugin header title can link back to the plugin root.
17
+ - e220589: Removed the unnecessary need to use `defineParams` callback from `PluginHeaderActionBlueprint`. It still works, but is no longer required.
18
+ - Updated dependencies
19
+ - @backstage/errors@1.3.0
20
+ - @backstage/filter-predicates@0.1.2
21
+
3
22
  ## 0.16.0-next.2
4
23
 
5
24
  ### 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;;;;"}
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
1211
+ * Opens a modal dialog with built-in dialog chrome and returns a handle to it.
1197
1212
  *
1198
- * This dialog can not be closed in any other way than calling the `close` method on the returned handle and providing a result.
1199
- *
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>;
@@ -0,0 +1,207 @@
1
+ import { z } from 'zod/v3';
2
+ import zodToJsonSchema from 'zod-to-json-schema';
3
+
4
+ function createDeprecatedConfigSchema(fields) {
5
+ const resolved = {};
6
+ for (const [key, field] of Object.entries(fields)) {
7
+ resolved[key] = resolveZodField(key, field(z));
8
+ }
9
+ return buildPortableSchema(resolved);
10
+ }
11
+ function createConfigSchema(fields) {
12
+ const resolved = {};
13
+ for (const [key, field] of Object.entries(fields)) {
14
+ resolved[key] = resolveField(key, field);
15
+ }
16
+ return buildPortableSchema(resolved);
17
+ }
18
+ function mergePortableSchemas(a, b) {
19
+ if (!a && !b) {
20
+ return void 0;
21
+ }
22
+ if (!a) {
23
+ return b;
24
+ }
25
+ if (!b) {
26
+ return a;
27
+ }
28
+ return buildPortableSchema({
29
+ ...a._fields,
30
+ ...b._fields
31
+ });
32
+ }
33
+ function buildPortableSchema(fields) {
34
+ function parse(input) {
35
+ if (input !== void 0 && input !== null && (typeof input !== "object" || Array.isArray(input))) {
36
+ throw new Error(
37
+ `Invalid config input, expected object but got ${Array.isArray(input) ? "array" : typeof input}`
38
+ );
39
+ }
40
+ const inputObj = input ?? {};
41
+ const result2 = {};
42
+ const errors = [];
43
+ for (const [key, field] of Object.entries(fields)) {
44
+ const validated = field.validate(inputObj[key]);
45
+ if ("errors" in validated) {
46
+ errors.push(...validated.errors);
47
+ } else if (validated.value !== void 0 || key in inputObj) {
48
+ result2[key] = validated.value;
49
+ }
50
+ }
51
+ if (errors.length > 0) {
52
+ throw new Error(errors.join("; "));
53
+ }
54
+ return result2;
55
+ }
56
+ const result = {
57
+ parse,
58
+ schema: void 0,
59
+ _fields: fields
60
+ };
61
+ let cached;
62
+ Object.defineProperty(result, "schema", {
63
+ get() {
64
+ if (!cached) {
65
+ const jsonSchema = buildObjectJsonSchema(fields);
66
+ const callable = Object.assign(
67
+ () => ({ schema: jsonSchema }),
68
+ jsonSchema
69
+ );
70
+ cached = callable;
71
+ }
72
+ return cached;
73
+ },
74
+ configurable: true,
75
+ enumerable: false
76
+ });
77
+ return result;
78
+ }
79
+ function resolveField(key, schema) {
80
+ if (isZodV3Type(schema)) {
81
+ throw new Error(
82
+ `Config schema for field '${key}' uses a Zod v3 schema, which is not supported by the \`configSchema\` option. Either use \`import { z } from 'zod/v4'\` from the zod v3 package, or upgrade to zod v4.`
83
+ );
84
+ }
85
+ if (isStandardSchema(schema)) {
86
+ if (!hasJsonSchemaConverter(schema)) {
87
+ throw new Error(
88
+ `Config schema for field '${key}' does not support JSON Schema conversion. Use a schema library that implements the Standard JSON Schema interface (like zod v4+).`
89
+ );
90
+ }
91
+ return resolveStandardField(key, schema);
92
+ }
93
+ throw new Error(
94
+ `Config schema for field '${key}' is not a valid Standard Schema`
95
+ );
96
+ }
97
+ function resolveZodField(key, schema) {
98
+ const wrapper = z.object({ [key]: schema });
99
+ return {
100
+ validate(value) {
101
+ const result = wrapper.safeParse({ [key]: value });
102
+ if (result.success) {
103
+ return { value: result.data[key] };
104
+ }
105
+ return { errors: result.error.issues.map(formatZodIssue) };
106
+ },
107
+ toJsonSchema() {
108
+ const wholeJsonSchema = zodToJsonSchema(wrapper);
109
+ return wholeJsonSchema.properties?.[key] ?? {};
110
+ },
111
+ required: !schema.isOptional()
112
+ };
113
+ }
114
+ function resolveStandardField(key, schema) {
115
+ const required = isFieldRequired(schema);
116
+ return {
117
+ validate(value) {
118
+ const result = schema["~standard"].validate(value);
119
+ if (result instanceof Promise) {
120
+ throw new Error(
121
+ `Config schema for '${key}' returned a Promise \u2014 async schemas are not supported`
122
+ );
123
+ }
124
+ if (result.issues) {
125
+ return {
126
+ errors: Array.from(result.issues).map(
127
+ (issue) => formatStandardIssue(key, issue)
128
+ )
129
+ };
130
+ }
131
+ return { value: result.value };
132
+ },
133
+ toJsonSchema() {
134
+ const raw = schema["~standard"].jsonSchema.input({ target: "draft-07" });
135
+ const { $schema: _, ...rest } = raw;
136
+ return rest;
137
+ },
138
+ required
139
+ };
140
+ }
141
+ function buildObjectJsonSchema(fields) {
142
+ const properties = {};
143
+ const required = [];
144
+ for (const [key, field] of Object.entries(fields)) {
145
+ properties[key] = field.toJsonSchema();
146
+ if (field.required) {
147
+ required.push(key);
148
+ }
149
+ }
150
+ const schema = {
151
+ type: "object",
152
+ properties,
153
+ additionalProperties: false
154
+ };
155
+ if (required.length > 0) {
156
+ schema.required = required;
157
+ }
158
+ return schema;
159
+ }
160
+ function isZodV3Type(value) {
161
+ return typeof value === "object" && value !== null && typeof value._parse === "function" && "_def" in value;
162
+ }
163
+ function isStandardSchema(value) {
164
+ return typeof value === "object" && value !== null && "~standard" in value && typeof value["~standard"]?.validate === "function";
165
+ }
166
+ function hasJsonSchemaConverter(schema) {
167
+ const std = schema["~standard"];
168
+ return typeof std?.jsonSchema?.input === "function";
169
+ }
170
+ function isFieldRequired(schema) {
171
+ const result = schema["~standard"].validate(void 0);
172
+ if (result instanceof Promise) {
173
+ return true;
174
+ }
175
+ return (result.issues?.length ?? 0) > 0;
176
+ }
177
+ function formatZodIssue(issue) {
178
+ if (issue.code === "invalid_union" && issue.unionErrors?.[0]?.issues?.[0]) {
179
+ return formatZodIssue(issue.unionErrors[0].issues[0]);
180
+ }
181
+ let message = issue.message;
182
+ if (message === "Required") {
183
+ message = "Missing required value";
184
+ }
185
+ if (issue.path.length) {
186
+ message += ` at '${issue.path.join(".")}'`;
187
+ }
188
+ return message;
189
+ }
190
+ function formatStandardIssue(fieldKey, issue) {
191
+ let message = issue.message;
192
+ if (message === "Required") {
193
+ message = "Missing required value";
194
+ }
195
+ const path = issue.path?.length ? `${fieldKey}.${issue.path.map(
196
+ (p) => typeof p === "object" ? p.key : p
197
+ ).join(".")}` : fieldKey;
198
+ return `${message} at '${path}'`;
199
+ }
200
+ function warnConfigSchemaPropDeprecation(callSite) {
201
+ console.warn(
202
+ `DEPRECATION WARNING: The \`config.schema\` option for extension config is deprecated. Use the \`configSchema\` option instead with Standard Schema values, for example \`configSchema: { title: z.string() }\` using zod v4 (or \`import { z } from 'zod/v4'\` from the zod v3 package). Declared at ${callSite}`
203
+ );
204
+ }
205
+
206
+ export { createConfigSchema, createDeprecatedConfigSchema, mergePortableSchemas, warnConfigSchemaPropDeprecation };
207
+ //# sourceMappingURL=createPortableSchema.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPortableSchema.esm.js","sources":["../../src/schema/createPortableSchema.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { JsonObject } from '@backstage/types';\nimport { z as zodV3, type ZodType } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport { PortableSchema } from './types';\n\n/**\n * The Standard Schema interface.\n * @public\n */\nexport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { type StandardSchemaV1 } from '@standard-schema/spec';\n\n/** @internal */\nexport function createDeprecatedConfigSchema(\n fields: Record<string, (zImpl: typeof zodV3) => ZodType>,\n): MergeablePortableSchema {\n const resolved: Record<string, ResolvedField> = {};\n\n for (const [key, field] of Object.entries(fields)) {\n resolved[key] = resolveZodField(key, field(zodV3));\n }\n\n return buildPortableSchema(resolved);\n}\n\n/**\n * Per-field resolved schema — validation is eager, JSON Schema is lazy.\n * @internal\n */\ninterface ResolvedField {\n validate(value: unknown): { value: unknown } | { errors: string[] };\n toJsonSchema(): JsonObject;\n required: boolean;\n}\n\n/**\n * Internal representation that carries per-field resolvers alongside the\n * public PortableSchema surface, enabling schema merging.\n * @internal\n */\nexport interface MergeablePortableSchema<TOutput = any, TInput = any>\n extends PortableSchema<TOutput, TInput> {\n /** @internal */\n readonly _fields: Record<string, ResolvedField>;\n}\n\n/**\n * Resolves each field, eagerly validates JSON Schema support, and returns\n * a PortableSchema whose JSON Schema conversion is lazy.\n * @internal\n */\nexport function createConfigSchema(\n fields: Record<string, StandardSchemaV1>,\n): MergeablePortableSchema {\n const resolved: Record<string, ResolvedField> = {};\n\n for (const [key, field] of Object.entries(fields)) {\n resolved[key] = resolveField(key, field);\n }\n\n return buildPortableSchema(resolved);\n}\n\n/**\n * Combines schemas from different sources for blueprint + override\n * composition. Each source may use a completely different schema library.\n * Because we track per-field resolvers, merging is just combining the\n * field maps.\n * @internal\n */\nexport function mergePortableSchemas<A, B>(\n a: MergeablePortableSchema<A> | undefined,\n b: MergeablePortableSchema<B> | undefined,\n): MergeablePortableSchema<A & B> | undefined {\n if (!a && !b) {\n return undefined;\n }\n if (!a) {\n return b as MergeablePortableSchema<A & B>;\n }\n if (!b) {\n return a as MergeablePortableSchema<A & B>;\n }\n\n return buildPortableSchema<A & B>({\n ...a._fields,\n ...b._fields,\n });\n}\n\n/**\n * Assembles resolved fields into a PortableSchema with per-field\n * validation (eager) and lazy JSON Schema generation.\n */\nfunction buildPortableSchema<TOutput = unknown>(\n fields: Record<string, ResolvedField>,\n): MergeablePortableSchema<TOutput> {\n function parse(input: unknown) {\n if (\n input !== undefined &&\n input !== null &&\n (typeof input !== 'object' || Array.isArray(input))\n ) {\n throw new Error(\n `Invalid config input, expected object but got ${\n Array.isArray(input) ? 'array' : typeof input\n }`,\n );\n }\n const inputObj = (input ?? {}) as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n const errors: string[] = [];\n\n for (const [key, field] of Object.entries(fields)) {\n const validated = field.validate(inputObj[key]);\n if ('errors' in validated) {\n errors.push(...validated.errors);\n } else if (validated.value !== undefined || key in inputObj) {\n result[key] = validated.value;\n }\n }\n\n if (errors.length > 0) {\n throw new Error(errors.join('; '));\n }\n\n return result as TOutput;\n }\n\n const result: MergeablePortableSchema<TOutput> = {\n parse,\n schema: undefined as any,\n _fields: fields,\n };\n\n // Lazy getter — computes JSON Schema on first access, then caches it.\n let cached: PortableSchema['schema'] | undefined;\n Object.defineProperty(result, 'schema', {\n get() {\n if (!cached) {\n const jsonSchema = buildObjectJsonSchema(fields);\n const callable = Object.assign(\n () => ({ schema: jsonSchema }),\n jsonSchema,\n );\n cached = callable as PortableSchema['schema'];\n }\n return cached;\n },\n configurable: true,\n enumerable: false,\n });\n\n return result;\n}\n\n/**\n * Wraps a single schema into a ResolvedField. Eagerly validates that\n * JSON Schema conversion will be possible, but defers the actual\n * conversion until toJsonSchema() is called.\n */\nfunction resolveField(key: string, schema: unknown): ResolvedField {\n if (isZodV3Type(schema)) {\n throw new Error(\n `Config schema for field '${key}' uses a Zod v3 schema, which is ` +\n `not supported by the \\`configSchema\\` option. Either use ` +\n `\\`import { z } from 'zod/v4'\\` from the zod v3 package, or ` +\n `upgrade to zod v4.`,\n );\n }\n if (isStandardSchema(schema)) {\n if (!hasJsonSchemaConverter(schema)) {\n throw new Error(\n `Config schema for field '${key}' does not support JSON Schema ` +\n `conversion. Use a schema library that implements the Standard ` +\n `JSON Schema interface (like zod v4+).`,\n );\n }\n return resolveStandardField(key, schema);\n }\n throw new Error(\n `Config schema for field '${key}' is not a valid Standard Schema`,\n );\n}\n\nfunction resolveZodField(key: string, schema: ZodType): ResolvedField {\n const wrapper = zodV3.object({ [key]: schema });\n\n return {\n validate(value) {\n const result = wrapper.safeParse({ [key]: value });\n if (result.success) {\n return { value: result.data[key] };\n }\n return { errors: result.error.issues.map(formatZodIssue) };\n },\n toJsonSchema() {\n const wholeJsonSchema = zodToJsonSchema(wrapper) as Record<string, any>;\n return (wholeJsonSchema.properties?.[key] ?? {}) as JsonObject;\n },\n required: !schema.isOptional(),\n };\n}\n\nfunction resolveStandardField(\n key: string,\n schema: StandardSchemaV1 & {\n '~standard': { jsonSchema: { input: Function } };\n },\n): ResolvedField {\n const required = isFieldRequired(schema);\n\n return {\n validate(value) {\n const result = schema['~standard'].validate(value);\n if (result instanceof Promise) {\n throw new Error(\n `Config schema for '${key}' returned a Promise — async schemas are not supported`,\n );\n }\n if (result.issues) {\n return {\n errors: Array.from(result.issues).map(issue =>\n formatStandardIssue(key, issue),\n ),\n };\n }\n return { value: result.value };\n },\n toJsonSchema() {\n const raw = schema['~standard'].jsonSchema.input({ target: 'draft-07' });\n const { $schema: _, ...rest } = raw;\n return rest as JsonObject;\n },\n required,\n };\n}\n\n/** Assembles per-field JSON Schemas into a single object-level JSON Schema. */\nfunction buildObjectJsonSchema(\n fields: Record<string, ResolvedField>,\n): JsonObject {\n const properties: Record<string, JsonObject> = {};\n const required: string[] = [];\n\n for (const [key, field] of Object.entries(fields)) {\n properties[key] = field.toJsonSchema();\n if (field.required) {\n required.push(key);\n }\n }\n\n const schema: Record<string, unknown> = {\n type: 'object',\n properties,\n additionalProperties: false,\n };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n return schema as JsonObject;\n}\n\nfunction isZodV3Type(value: unknown): value is ZodType {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as any)._parse === 'function' &&\n '_def' in value\n );\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n return (\n typeof value === 'object' &&\n value !== null &&\n '~standard' in value &&\n typeof (value as any)['~standard']?.validate === 'function'\n );\n}\n\nfunction hasJsonSchemaConverter(\n schema: StandardSchemaV1,\n): schema is StandardSchemaV1 & {\n '~standard': { jsonSchema: { input: Function } };\n} {\n const std = schema['~standard'] as any;\n return typeof std?.jsonSchema?.input === 'function';\n}\n\nfunction isFieldRequired(schema: StandardSchemaV1): boolean {\n const result = schema['~standard'].validate(undefined);\n if (result instanceof Promise) {\n return true;\n }\n return (result.issues?.length ?? 0) > 0;\n}\n\nfunction formatZodIssue(issue: {\n code: string;\n message: string;\n path: Array<string | number>;\n unionErrors?: Array<{ issues: Array<any> }>;\n}): string {\n if (issue.code === 'invalid_union' && issue.unionErrors?.[0]?.issues?.[0]) {\n return formatZodIssue(issue.unionErrors[0].issues[0]);\n }\n let message = issue.message;\n if (message === 'Required') {\n message = 'Missing required value';\n }\n if (issue.path.length) {\n message += ` at '${issue.path.join('.')}'`;\n }\n return message;\n}\n\nfunction formatStandardIssue(\n fieldKey: string,\n issue: StandardSchemaV1.Issue,\n): string {\n let message = issue.message;\n if (message === 'Required') {\n message = 'Missing required value';\n }\n const path = issue.path?.length\n ? `${fieldKey}.${issue.path\n .map((p: PropertyKey | StandardSchemaV1.PathSegment) =>\n typeof p === 'object' ? p.key : p,\n )\n .join('.')}`\n : fieldKey;\n return `${message} at '${path}'`;\n}\n\n/** @internal */\nexport function warnConfigSchemaPropDeprecation(callSite: string) {\n // eslint-disable-next-line no-console\n console.warn(\n `DEPRECATION WARNING: The \\`config.schema\\` option for extension config is deprecated. ` +\n `Use the \\`configSchema\\` option instead with Standard Schema values, for example ` +\n `\\`configSchema: { title: z.string() }\\` using zod v4 ` +\n `(or \\`import { z } from 'zod/v4'\\` from the zod v3 package). ` +\n `Declared at ${callSite}`,\n );\n}\n"],"names":["zodV3","result"],"mappings":"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"}