diff --git a/.changeset/better-bottles-smoke.md b/.changeset/better-bottles-smoke.md new file mode 100644 index 0000000000..14d3747fac --- /dev/null +++ b/.changeset/better-bottles-smoke.md @@ -0,0 +1,5 @@ +--- +'@backstage/canon': minor +--- + +Added a new Tooltip component to Canon. diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md index 4f4a52ffd3..e9527d4c35 100644 --- a/packages/canon/report.api.md +++ b/packages/canon/report.api.md @@ -12,6 +12,7 @@ import { default as React_2 } from 'react'; import * as React_3 from 'react'; import { ReactNode } from 'react'; import { RefAttributes } from 'react'; +import { Tooltip as Tooltip_2 } from '@base-ui-components/react/tooltip'; // @public (undocumented) export type AlignItems = 'stretch' | 'start' | 'center' | 'end'; @@ -972,6 +973,32 @@ export interface TextProps { weight?: 'regular' | 'bold' | Partial>; } +// @public (undocumented) +export const Tooltip: { + Provider: React_2.FC; + Root: React_2.FC; + Trigger: React_2.ForwardRefExoticComponent< + Omit, 'ref'> & + React_2.RefAttributes + >; + Portal: typeof Tooltip_2.Portal; + Positioner: React_2.ForwardRefExoticComponent< + Omit< + Tooltip_2.Positioner.Props & React_2.RefAttributes, + 'ref' + > & + React_2.RefAttributes + >; + Popup: React_2.ForwardRefExoticComponent< + Omit, 'ref'> & + React_2.RefAttributes + >; + Arrow: React_2.ForwardRefExoticComponent< + Omit, 'ref'> & + React_2.RefAttributes + >; +}; + // @public (undocumented) export const useIcons: () => IconContextProps; diff --git a/packages/canon/src/components/Tooltip/Tooltip.stories.tsx b/packages/canon/src/components/Tooltip/Tooltip.stories.tsx new file mode 100644 index 0000000000..4c3168a934 --- /dev/null +++ b/packages/canon/src/components/Tooltip/Tooltip.stories.tsx @@ -0,0 +1,81 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Tooltip } from './Tooltip'; +import { Button } from '../Button/Button'; + +const meta = { + title: 'Components/Tooltip', + component: Tooltip.Root, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: ( + <> + ( + + )} + /> + + + Nice! + + + + ), + }, +}; + +export const Open: Story = { + args: { + ...Default.args, + open: true, + }, +}; + +export const WithArrow: Story = { + args: { + open: true, + children: ( + <> + ( + + )} + /> + + + + + Nice! + + + + + ), + }, +}; diff --git a/packages/canon/src/components/Tooltip/Tooltip.styles.css b/packages/canon/src/components/Tooltip/Tooltip.styles.css new file mode 100644 index 0000000000..9ae4d42722 --- /dev/null +++ b/packages/canon/src/components/Tooltip/Tooltip.styles.css @@ -0,0 +1,83 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.canon-TooltipPopup { + box-sizing: border-box; + font-size: 0.875rem; + line-height: 1.25rem; + display: flex; + flex-direction: column; + padding: 0.25rem 0.5rem; + border-radius: 0.375rem; + background-color: canvas; + transform-origin: var(--transform-origin); + transition: transform 150ms, opacity 150ms; + background-color: var(--canon-bg-surface-1); + color: var(--canon-fg-primary); + outline: 1px solid var(--canon-border); + box-shadow: 0 10px 15px -3px var(--canon-border), + 0 4px 6px -4px var(--canon-border); + + &[data-starting-style], + &[data-ending-style] { + opacity: 0; + transform: scale(0.9); + } + + &[data-instant] { + transition-duration: 0ms; + } +} + +.canon-TooltipArrow { + display: flex; + + &[data-side='top'] { + bottom: -8px; + rotate: 180deg; + } + + &[data-side='bottom'] { + top: -8px; + rotate: 0deg; + } + + &[data-side='left'] { + right: -13px; + rotate: 90deg; + } + + &[data-side='right'] { + left: -13px; + rotate: -90deg; + } +} + +.canon-TooltipArrowFill { + fill: var(--canon-bg-surface-1); +} + +.canon-TooltipArrowOuterStroke { + @media (prefers-color-scheme: light) { + fill: var(--canon-border); + } +} + +.canon-TooltipArrowInnerStroke { + @media (prefers-color-scheme: dark) { + /* fill: var(--canon-border); */ + } +} diff --git a/packages/canon/src/components/Tooltip/Tooltip.tsx b/packages/canon/src/components/Tooltip/Tooltip.tsx new file mode 100644 index 0000000000..ce43982a7a --- /dev/null +++ b/packages/canon/src/components/Tooltip/Tooltip.tsx @@ -0,0 +1,93 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Tooltip as TooltipPrimitive } from '@base-ui-components/react/tooltip'; +import clsx from 'clsx'; + +const TooltipTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName; + +const TooltipPositioner = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TooltipPositioner.displayName = TooltipPrimitive.Positioner.displayName; + +const TooltipPopup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TooltipPopup.displayName = TooltipPrimitive.Popup.displayName; + +const TooltipArrow = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + + +)); +TooltipArrow.displayName = TooltipPrimitive.Arrow.displayName; + +/** @public */ +export const Tooltip = { + Provider: TooltipPrimitive.Provider, + Root: TooltipPrimitive.Root, + Trigger: TooltipTrigger, + Portal: TooltipPrimitive.Portal, + Positioner: TooltipPositioner, + Popup: TooltipPopup, + Arrow: TooltipArrow, +}; diff --git a/packages/canon/src/components/Tooltip/index.ts b/packages/canon/src/components/Tooltip/index.ts new file mode 100644 index 0000000000..cf97688854 --- /dev/null +++ b/packages/canon/src/components/Tooltip/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './Tooltip'; diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index d7d99bbe91..c515762716 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -27,3 +27,4 @@ @import '../components/Input/Input.styles.css'; @import '../components/Field/Field.styles.css'; @import '../components/Link/styles.css'; +@import '../components/Tooltip/Tooltip.styles.css'; diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index 18dad55e89..0fae261531 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -38,6 +38,7 @@ export * from './components/Checkbox'; export * from './components/Table'; export * from './components/Input'; export * from './components/Field'; +export * from './components/Tooltip'; // Types export * from './types';