diff --git a/.changeset/huge-paws-design.md b/.changeset/huge-paws-design.md new file mode 100644 index 0000000000..8d90435480 --- /dev/null +++ b/.changeset/huge-paws-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +We are motion away from `motion` to use `gsap` instead to make Backstage UI backward compatible with React 17. diff --git a/packages/types/report.api.md b/packages/types/report.api.md index b6bfae0862..efd46b81c3 100644 --- a/packages/types/report.api.md +++ b/packages/types/report.api.md @@ -64,7 +64,7 @@ export type JsonValue = JsonObject | JsonArray | JsonPrimitive; // @public export type Observable = { [Symbol.observable](): Observable; - subscribe(observer: Observer): Subscription; + subscribe(observer: Observer_2): Subscription; subscribe( onNext?: (value: T) => void, onError?: (error: Error) => void, @@ -73,11 +73,12 @@ export type Observable = { }; // @public -export type Observer = { +type Observer_2 = { next?(value: T): void; error?(error: Error): void; complete?(): void; }; +export { Observer_2 as Observer }; // @public export type Subscription = { diff --git a/packages/ui/package.json b/packages/ui/package.json index c5be84a257..8c0f569bd7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -42,10 +42,11 @@ }, "dependencies": { "@base-ui-components/react": "1.0.0-alpha.7", + "@gsap/react": "^2.1.2", "@remixicon/react": "^4.6.0", "@tanstack/react-table": "^8.21.3", "clsx": "^2.1.1", - "motion": "^12.20.1", + "gsap": "^3.13.0", "react-aria-components": "^1.10.1" }, "devDependencies": { diff --git a/packages/ui/src/components/Header/HeaderToolbar.tsx b/packages/ui/src/components/Header/HeaderToolbar.tsx index cc165dc661..20f0519707 100644 --- a/packages/ui/src/components/Header/HeaderToolbar.tsx +++ b/packages/ui/src/components/Header/HeaderToolbar.tsx @@ -22,8 +22,12 @@ import type { HeaderToolbarProps } from './types'; import { ButtonIcon } from '../ButtonIcon'; import { Menu } from '../Menu'; import { Text } from '../Text'; -import { motion, useScroll, useTransform } from 'motion/react'; import { useNavigate, useHref } from 'react-router-dom'; +import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; +import { useGSAP } from '@gsap/react'; + +gsap.registerPlugin(ScrollTrigger); /** * A component that renders a toolbar. @@ -42,13 +46,12 @@ export const HeaderToolbar = (props: HeaderToolbarProps) => { } = props; const { classNames } = useStyles('Header'); let navigate = useNavigate(); - const { scrollY } = useScroll(); - const breadcrumbOpacity = useTransform(scrollY, [80, 120], [0, 1]); // Refs for collision detection const toolbarWrapperRef = useRef(null); const toolbarContentRef = useRef(null); const toolbarControlsRef = useRef(null); + const breadcrumbsRef = useRef(null); // State for breadcrumb visibility const [showBreadcrumbs, setShowBreadcrumbs] = useState(true); @@ -96,6 +99,19 @@ export const HeaderToolbar = (props: HeaderToolbarProps) => { }; }, []); + useGSAP(() => { + gsap.to(breadcrumbsRef.current, { + scrollTrigger: { + start: '10% 10%', + end: '20% 20%', + scrub: true, + }, + opacity: 1, + duration: 1, + ease: 'power2.inOut', + }); + }); + const titleContent = ( <>
{icon || }
@@ -116,10 +132,11 @@ export const HeaderToolbar = (props: HeaderToolbarProps) => {
{titleContent}
)} {breadcrumbs && ( - @@ -144,7 +161,7 @@ export const HeaderToolbar = (props: HeaderToolbarProps) => { )} ))} - + )}
diff --git a/yarn.lock b/yarn.lock index 5e40cbb6f1..72dceeed70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8458,6 +8458,7 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@base-ui-components/react": "npm:1.0.0-alpha.7" + "@gsap/react": "npm:^2.1.2" "@remixicon/react": "npm:^4.6.0" "@storybook/addon-essentials": "npm:^8.6.12" "@storybook/addon-interactions": "npm:^8.6.12" @@ -8476,9 +8477,9 @@ __metadata: eslint-plugin-storybook: "npm:^0.12.0" glob: "npm:^11.0.1" globals: "npm:^15.11.0" + gsap: "npm:^3.13.0" lightningcss: "npm:^1.29.1" mini-css-extract-plugin: "npm:^2.9.2" - motion: "npm:^12.20.1" react: "npm:^18.0.2" react-aria-components: "npm:^1.10.1" react-dom: "npm:^18.0.2" @@ -10316,6 +10317,16 @@ __metadata: languageName: node linkType: hard +"@gsap/react@npm:^2.1.2": + version: 2.1.2 + resolution: "@gsap/react@npm:2.1.2" + peerDependencies: + gsap: ^3.12.5 + react: ">=17" + checksum: 10/48e78bbb31a4ec5a75aab6ea69ec3f4df0bb7cff0c8ebfcdc14553cb8e35f54b7fcf94f933e2aa65fd977135aaac87b855007d376504f1bb93a74328ba1dc0cb + languageName: node + linkType: hard + "@headlessui/react@npm:^1.7.15": version: 1.7.17 resolution: "@headlessui/react@npm:1.7.17" @@ -32319,28 +32330,6 @@ __metadata: languageName: node linkType: hard -"framer-motion@npm:^12.20.1": - version: 12.20.1 - resolution: "framer-motion@npm:12.20.1" - dependencies: - motion-dom: "npm:^12.20.1" - motion-utils: "npm:^12.19.0" - 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/ba36e76dbf66c856f0c5d3cfb80973bb0ef95ca9169fc16b22560a7bc55fbedcf63205266dba7beecac5152c4cd140097ff504c5d529beffca86cd85f97bf5e3 - languageName: node - linkType: hard - "framer-motion@npm:^6.5.1": version: 6.5.1 resolution: "framer-motion@npm:6.5.1" @@ -33438,6 +33427,13 @@ __metadata: languageName: node linkType: hard +"gsap@npm:^3.13.0": + version: 3.13.0 + resolution: "gsap@npm:3.13.0" + checksum: 10/1908d51cbdf8f0bec8a69919af352d743a06529639a89f750f1c02e9a165d3ea816f867569df222ee7bfc14e23e268ebeb51dc5df0687fa7918ddd5d3b3efaec + languageName: node + linkType: hard + "gtoken@npm:^7.0.0": version: 7.0.1 resolution: "gtoken@npm:7.0.1" @@ -39809,43 +39805,6 @@ __metadata: languageName: node linkType: hard -"motion-dom@npm:^12.20.1": - version: 12.20.1 - resolution: "motion-dom@npm:12.20.1" - dependencies: - motion-utils: "npm:^12.19.0" - checksum: 10/b92d733fdfe3f66511f73c7f84f9483a0529eadf6ad2ab633cef584d161bcd1af786d257776e1fe7cd2b4e2c9c10912773f96ce9e2bd5b45c6c33ba6d9edfe86 - languageName: node - linkType: hard - -"motion-utils@npm:^12.19.0": - version: 12.19.0 - resolution: "motion-utils@npm:12.19.0" - checksum: 10/a6fe6b329bf4e2070bb95788218f36f0d7ea6cc3098e6ea2646ed68d5be88d25fa30e55284463ace78d19a5e19714875a7b70055bd86ae6e52a5fdee08438470 - languageName: node - linkType: hard - -"motion@npm:^12.20.1": - version: 12.20.1 - resolution: "motion@npm:12.20.1" - dependencies: - framer-motion: "npm:^12.20.1" - 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/49057c8d5812207209ca078a67ee7467d2dca7abacdcf2db486cd28c3ca105a7fe2504c34407df201c85035f6df1c806954af94914417ee89d721133fc4e92ce - languageName: node - linkType: hard - "mri@npm:1.1.4": version: 1.1.4 resolution: "mri@npm:1.1.4"