From 69a323b9c4576b4286c384fd352de4e42b5872d8 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 27 Jan 2026 16:13:21 +0000 Subject: [PATCH] New pass on toast Signed-off-by: Charles de Dreuille --- packages/ui/package.json | 2 + .../ui/src/components/Toast/Toast.module.css | 11 - packages/ui/src/components/Toast/Toast.tsx | 66 +++--- .../ui/src/components/Toast/ToastQueue.ts | 2 +- .../ui/src/components/Toast/ToastRegion.tsx | 60 ++++-- .../ui/src/components/Toast/definition.ts | 1 + packages/ui/src/components/Toast/types.ts | 14 +- yarn.lock | 196 +++++++++++++++++- 8 files changed, 278 insertions(+), 74 deletions(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index 671be132e8..5749d55c22 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -47,9 +47,11 @@ }, "dependencies": { "@backstage/version-bridge": "workspace:^", + "@react-aria/toast": "^3.0.9", "@remixicon/react": "^4.6.0", "@tanstack/react-table": "^8.21.3", "clsx": "^2.1.1", + "motion": "^12.29.2", "react-aria-components": "^1.14.0" }, "devDependencies": { diff --git a/packages/ui/src/components/Toast/Toast.module.css b/packages/ui/src/components/Toast/Toast.module.css index df7add7efc..efdcf1bea1 100644 --- a/packages/ui/src/components/Toast/Toast.module.css +++ b/packages/ui/src/components/Toast/Toast.module.css @@ -193,17 +193,6 @@ } } - /* Entering and exiting states */ - .bui-Toast[data-entering] { - transform: translateY(calc(100% + 2rem)) scale(1); - opacity: 0; - } - - .bui-Toast[data-exiting] { - transform: translateY(calc(100% + 2rem)) scale(var(--toast-scale)); - opacity: 0; - } - /* Reduced motion */ @media (prefers-reduced-motion: reduce) { .bui-Toast { diff --git a/packages/ui/src/components/Toast/Toast.tsx b/packages/ui/src/components/Toast/Toast.tsx index 221a66c468..c78f970901 100644 --- a/packages/ui/src/components/Toast/Toast.tsx +++ b/packages/ui/src/components/Toast/Toast.tsx @@ -14,13 +14,10 @@ * limitations under the License. */ -import { forwardRef, Ref, isValidElement, ReactElement } from 'react'; -import { - UNSTABLE_Toast as RAToast, - UNSTABLE_ToastContent as RAToastContent, - Text, - Button as RAButton, -} from 'react-aria-components'; +import { forwardRef, Ref, isValidElement, ReactElement, useRef } from 'react'; +import { motion } from 'motion/react'; +import { useToast } from '@react-aria/toast'; +import { useButton } from 'react-aria'; import { RiInformationLine, RiCheckLine, @@ -31,6 +28,8 @@ import { import type { ToastProps } from './types'; import { useDefinition } from '../../hooks/useDefinition'; import { ToastDefinition } from './definition'; +import type { ToastState } from 'react-stately'; +import type { ToastContent } from './types'; /** * A Toast displays a brief, temporary notification of actions, errors, or other events in an application. @@ -66,12 +65,17 @@ import { ToastDefinition } from './definition'; * @public */ export const Toast = forwardRef( - (props: ToastProps, ref: Ref) => { - const { ownProps, restProps, dataAttributes } = useDefinition( - ToastDefinition, - props, - ); - const { classes, toast, index = 0, status, icon } = ownProps; + (props: ToastProps, _forwardedRef: Ref) => { + const { ownProps, dataAttributes } = useDefinition(ToastDefinition, props); + const { classes, toast, state, index = 0, status, icon } = ownProps; + + const ref = useRef(null); + const closeButtonRef = useRef(null); + + const { toastProps, titleProps, descriptionProps, closeButtonProps } = + useToast({ toast }, state, ref); + + const { buttonProps } = useButton(closeButtonProps, closeButtonRef); // Get content from toast const content = toast.content; @@ -112,36 +116,46 @@ export const Toast = forwardRef( const statusIcon = getStatusIcon(); return ( - - +
{statusIcon &&
{statusIcon}
}
- +
{content.title} - +
{content.description && ( - +
{content.description} - +
)}
- - +
+ + ); }, ); diff --git a/packages/ui/src/components/Toast/ToastQueue.ts b/packages/ui/src/components/Toast/ToastQueue.ts index cdf2ec05fc..cb26a2e916 100644 --- a/packages/ui/src/components/Toast/ToastQueue.ts +++ b/packages/ui/src/components/Toast/ToastQueue.ts @@ -43,5 +43,5 @@ import type { ToastContent } from './types'; * @public */ export const toastQueue = new RAToastQueue({ - maxVisibleToasts: 3, + maxVisibleToasts: 5, }); diff --git a/packages/ui/src/components/Toast/ToastRegion.tsx b/packages/ui/src/components/Toast/ToastRegion.tsx index 7bf6c00e9f..0e2e32322f 100644 --- a/packages/ui/src/components/Toast/ToastRegion.tsx +++ b/packages/ui/src/components/Toast/ToastRegion.tsx @@ -14,9 +14,11 @@ * limitations under the License. */ -import { forwardRef, Ref, useEffect, useState } from 'react'; -import { UNSTABLE_ToastRegion as RAToastRegion } from 'react-aria-components'; -import type { ToastRegionProps } from './types'; +import { forwardRef, Ref, useEffect, useState, useRef } from 'react'; +import { useToastRegion } from '@react-aria/toast'; +import { AnimatePresence } from 'motion/react'; +import type { QueuedToast, ToastState } from 'react-stately'; +import type { ToastRegionProps, ToastContent } from './types'; import { useDefinition } from '../../hooks/useDefinition'; import { ToastRegionDefinition } from './definition'; import { Toast } from './Toast'; @@ -51,41 +53,57 @@ import { Toast } from './Toast'; * @public */ export const ToastRegion = forwardRef( - (props: ToastRegionProps, ref: Ref) => { + (props: ToastRegionProps, _ref: Ref) => { const { ownProps, restProps, dataAttributes } = useDefinition( ToastRegionDefinition, props, ); const { classes, queue, className } = ownProps; - // Track visible toast keys to determine index - const [visibleToasts, setVisibleToasts] = useState([]); + const [, forceUpdate] = useState({}); + const ref = useRef(null); useEffect(() => { - const updateToasts = () => { - setVisibleToasts(queue.visibleToasts.map(t => t.key)); - }; - - // Subscribe to queue changes - const unsubscribe = queue.subscribe(updateToasts); - updateToasts(); // Initial update - + // Subscribe to queue changes to trigger re-renders + const unsubscribe = queue.subscribe(() => forceUpdate({})); return unsubscribe; }, [queue]); + const state: ToastState = { + visibleToasts: queue.visibleToasts, + add: (content: ToastContent, options?: any) => + queue.add(content, options), + close: (key: string) => queue.close(key), + pauseAll: () => queue.pauseAll(), + resumeAll: () => queue.resumeAll(), + }; + + const { regionProps } = useToastRegion({}, state, ref); + return ( - - {({ toast }) => { - const index = visibleToasts.indexOf(toast.key); - return = 0 ? index : 0} />; - }} - +
    + + {queue.visibleToasts.map( + (toast: QueuedToast, arrayIndex: number) => { + // Reverse index so newest toast (at end of array) gets index 0 + const index = queue.visibleToasts.length - 1 - arrayIndex; + return ( +
  1. + +
  2. + ); + }, + )} +
    +
+ ); }, ); diff --git a/packages/ui/src/components/Toast/definition.ts b/packages/ui/src/components/Toast/definition.ts index d9d45f2e9b..a149cc1521 100644 --- a/packages/ui/src/components/Toast/definition.ts +++ b/packages/ui/src/components/Toast/definition.ts @@ -35,6 +35,7 @@ export const ToastDefinition = defineComponent()({ surface: 'container', propDefs: { toast: {}, + state: {}, index: {}, status: { dataAttribute: true }, icon: {}, diff --git a/packages/ui/src/components/Toast/types.ts b/packages/ui/src/components/Toast/types.ts index 457857a86e..dc0d9b667f 100644 --- a/packages/ui/src/components/Toast/types.ts +++ b/packages/ui/src/components/Toast/types.ts @@ -16,6 +16,7 @@ import type { ReactElement, ReactNode } from 'react'; import type { UNSTABLE_ToastQueue as RAToastQueue } from 'react-aria-components'; +import type { ToastState, QueuedToast } from 'react-stately'; import type { Responsive } from '../../types'; /** @@ -35,16 +36,15 @@ export interface ToastContent { /** * Own props for the Toast component - * @public + * @internal */ export type ToastOwnProps = { /** Toast object from the queue */ - toast: { - key: string; - content: ToastContent; - }; + toast: QueuedToast; + /** Toast state for hooks */ + state: ToastState; /** Index of the toast in the stack (0 = frontmost) */ - index?: number; + index: number; /** Override status from content */ status?: Responsive<'info' | 'success' | 'warning' | 'danger'>; /** Override icon from content */ @@ -53,7 +53,7 @@ export type ToastOwnProps = { /** * Properties for {@link Toast} - * @public + * @internal */ export interface ToastProps extends ToastOwnProps {} diff --git a/yarn.lock b/yarn.lock index 318b7c8629..bab3d96844 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8114,6 +8114,7 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@backstage/version-bridge": "workspace:^" + "@react-aria/toast": "npm:^3.0.9" "@remixicon/react": "npm:^4.6.0" "@tanstack/react-table": "npm:^8.21.3" "@types/react": "npm:^18.0.0" @@ -8122,6 +8123,7 @@ __metadata: eslint-plugin-storybook: "npm:^10.3.0-alpha.1" glob: "npm:^11.0.1" globals: "npm:^15.11.0" + motion: "npm:^12.29.2" react: "npm:^18.0.2" react-aria-components: "npm:^1.14.0" react-dom: "npm:^18.0.2" @@ -22931,6 +22933,19 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/project-service@npm:8.52.0": + version: 8.52.0 + resolution: "@typescript-eslint/project-service@npm:8.52.0" + dependencies: + "@typescript-eslint/tsconfig-utils": "npm:^8.52.0" + "@typescript-eslint/types": "npm:^8.52.0" + debug: "npm:^4.4.3" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10/bfa786007ed4a603fb8f31c6e354f0ba0cca576b03e402584ae3cf0d674f07adfbde9e976a5bf165fa44c484d4b4f310bd18b34d1b0e75b4210253edbdaabb87 + languageName: node + linkType: hard + "@typescript-eslint/project-service@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/project-service@npm:8.54.0" @@ -22954,6 +22969,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.52.0": + version: 8.52.0 + resolution: "@typescript-eslint/scope-manager@npm:8.52.0" + dependencies: + "@typescript-eslint/types": "npm:8.52.0" + "@typescript-eslint/visitor-keys": "npm:8.52.0" + checksum: 10/89d9c04cd2567e6aa9adcbe85e2eab24fbc64bde5a33c688764e7c896e9a02c06aad2ec88e8bdc4d5bfabadbc510906a0cb4f3e0b73a5b80d10218f7a6a4ea27 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:8.54.0, @typescript-eslint/scope-manager@npm:^8.51.0": version: 8.54.0 resolution: "@typescript-eslint/scope-manager@npm:8.54.0" @@ -22964,6 +22989,15 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/tsconfig-utils@npm:8.52.0, @typescript-eslint/tsconfig-utils@npm:^8.52.0": + version: 8.52.0 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.52.0" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10/5b26227ab549e20a6b15725a4f8373acb70ae1c83570c8d670e242bfcd22ac0c9111d4d28ea16ee3939572caacce50e113388ce943f238fc2ca17f6c5a040cd2 + languageName: node + linkType: hard + "@typescript-eslint/tsconfig-utils@npm:8.54.0, @typescript-eslint/tsconfig-utils@npm:^8.54.0": version: 8.54.0 resolution: "@typescript-eslint/tsconfig-utils@npm:8.54.0" @@ -22996,6 +23030,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.52.0, @typescript-eslint/types@npm:^8.52.0": + version: 8.52.0 + resolution: "@typescript-eslint/types@npm:8.52.0" + checksum: 10/05a630c5d25cce74d1bfa51027f1232f2e8a97a8f483ce0274e928373b4633cdf713be53eca39926f0372d52a3335f13786c7910d2edfd546a0cf1d66b3bcf51 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:8.54.0, @typescript-eslint/types@npm:^8.54.0": version: 8.54.0 resolution: "@typescript-eslint/types@npm:8.54.0" @@ -23022,6 +23063,25 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:8.52.0": + version: 8.52.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.52.0" + dependencies: + "@typescript-eslint/project-service": "npm:8.52.0" + "@typescript-eslint/tsconfig-utils": "npm:8.52.0" + "@typescript-eslint/types": "npm:8.52.0" + "@typescript-eslint/visitor-keys": "npm:8.52.0" + debug: "npm:^4.4.3" + minimatch: "npm:^9.0.5" + semver: "npm:^7.7.3" + tinyglobby: "npm:^0.2.15" + ts-api-utils: "npm:^2.4.0" + peerDependencies: + typescript: ">=4.8.4 <6.0.0" + checksum: 10/4e699f44a05e9c487531557a1eaf6412a97f370ec946a03596c8d445f584c3d17e9aa34cde5ce8998ae9d6908c1daffb2c9b523cb07e5988cf249eae6dea50fd + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:8.54.0, @typescript-eslint/typescript-estree@npm:^8.23.0": version: 8.54.0 resolution: "@typescript-eslint/typescript-estree@npm:8.54.0" @@ -23041,7 +23101,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.48.0, @typescript-eslint/utils@npm:^8.51.0": +"@typescript-eslint/utils@npm:8.54.0, @typescript-eslint/utils@npm:^8.48.0": version: 8.54.0 resolution: "@typescript-eslint/utils@npm:8.54.0" dependencies: @@ -23056,6 +23116,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.51.0": + version: 8.52.0 + resolution: "@typescript-eslint/utils@npm:8.52.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/scope-manager": "npm:8.52.0" + "@typescript-eslint/types": "npm:8.52.0" + "@typescript-eslint/typescript-estree": "npm:8.52.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ">=4.8.4 <6.0.0" + checksum: 10/11a02ab0fd26bb1284dfa8c02d40c54cabd3aa795e82ab26b060ea3839998c28a41822b075f9d23fb51e291e465147213166c8ddaf3c8d5807e70b0a4345d967 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:^7.0.0": version: 7.18.0 resolution: "@typescript-eslint/utils@npm:7.18.0" @@ -23080,6 +23155,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:8.52.0": + version: 8.52.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.52.0" + dependencies: + "@typescript-eslint/types": "npm:8.52.0" + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10/4d841402cc65e876382ede464b68cf167c7d24905b15225c472516bb759140abbef02f250c6335ca35327f7328975ff3b28c3249a5183319cfd01f1d5541e3c1 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:8.54.0": version: 8.54.0 resolution: "@typescript-eslint/visitor-keys@npm:8.54.0" @@ -29250,9 +29335,9 @@ __metadata: linkType: hard "detect-libc@npm:^2.0.0": - version: 2.1.2 - resolution: "detect-libc@npm:2.1.2" - checksum: 10/b736c8d97d5d46164c0d1bed53eb4e6a3b1d8530d460211e2d52f1c552875e706c58a5376854e4e54f8b828c9cada58c855288c968522eb93ac7696d65970766 + version: 2.0.3 + resolution: "detect-libc@npm:2.0.3" + checksum: 10/b4ea018d623e077bd395f168a9e81db77370dde36a5b01d067f2ad7989924a81d31cb547ff764acb2aa25d50bb7fdde0b0a93bec02212b0cb430621623246d39 languageName: node linkType: hard @@ -32169,7 +32254,17 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.11, follow-redirects@npm:^1.15.6": +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.6": + version: 1.15.6 + resolution: "follow-redirects@npm:1.15.6" + peerDependenciesMeta: + debug: + optional: true + checksum: 10/70c7612c4cab18e546e36b991bbf8009a1a41cf85354afe04b113d1117569abf760269409cb3eb842d9f7b03d62826687086b081c566ea7b1e6613cf29030bf7 + languageName: node + linkType: hard + +"follow-redirects@npm:^1.15.11": version: 1.15.11 resolution: "follow-redirects@npm:1.15.11" peerDependenciesMeta: @@ -32374,6 +32469,28 @@ __metadata: languageName: node linkType: hard +"framer-motion@npm:^12.29.2": + version: 12.29.2 + resolution: "framer-motion@npm:12.29.2" + dependencies: + motion-dom: "npm:^12.29.2" + motion-utils: "npm:^12.29.2" + tslib: "npm:^2.4.0" + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10/13ea43efa814e4df1f3a0bf7ee6c1736f3f01b96cb677e560b62d58db8768f00a53c17156bb5bf6bf06b786370468495dbb6b0a83e3b5b5289e5235046ccb03b + languageName: node + linkType: hard + "framer-motion@npm:^6.5.1": version: 6.5.1 resolution: "framer-motion@npm:6.5.1" @@ -34956,7 +35073,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0, is-core-module@npm:^2.16.1": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" dependencies: @@ -39787,6 +39904,43 @@ __metadata: languageName: node linkType: hard +"motion-dom@npm:^12.29.2": + version: 12.29.2 + resolution: "motion-dom@npm:12.29.2" + dependencies: + motion-utils: "npm:^12.29.2" + checksum: 10/d1eeb6840363cc2b4d1e1c2d9a91becc117bb64747482b1a99f7f2d4da709f049c9544c3a566c641cada368037019c0fafd3e7cf56f0477e88d65e9886bcdc40 + languageName: node + linkType: hard + +"motion-utils@npm:^12.29.2": + version: 12.29.2 + resolution: "motion-utils@npm:12.29.2" + checksum: 10/ae5f9be58c07939af72334894ed1a18653d724946182a718dc3d11268ef26e63804c3f16dee5a6110596d4406b539c4513822b74f86adebef9488601c34b18b7 + languageName: node + linkType: hard + +"motion@npm:^12.29.2": + version: 12.29.2 + resolution: "motion@npm:12.29.2" + dependencies: + framer-motion: "npm:^12.29.2" + tslib: "npm:^2.4.0" + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10/0480a984192dd0f884709a007c1d28f31ff5fcdecb6674517edbe11ac0e318efc845373f35800e0606899613e6617ec87b1c09d5ecf3f5a5aeb3eb25fef22c7d + languageName: node + linkType: hard + "mri@npm:1.1.4": version: 1.1.4 resolution: "mri@npm:1.1.4" @@ -45405,7 +45559,20 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": +"resolve@npm:^1.1.6, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": + version: 1.22.10 + resolution: "resolve@npm:1.22.10" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/0a398b44da5c05e6e421d70108822c327675febb880eebe905587628de401854c61d5df02866ff34fc4cb1173a51c9f0e84a94702738df3611a62e2acdc68181 + languageName: node + linkType: hard + +"resolve@npm:^1.1.7": version: 1.22.11 resolution: "resolve@npm:1.22.11" dependencies: @@ -45444,7 +45611,20 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin, resolve@patch:resolve@npm%3A~1.22.2#optional!builtin": + version: 1.22.10 + resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/d4d878bfe3702d215ea23e75e0e9caf99468e3db76f5ca100d27ebdc527366fee3877e54bce7d47cc72ca8952fc2782a070d238bfa79a550eeb0082384c3b81a + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin": version: 1.22.11 resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" dependencies: