diff --git a/packages/canon/css/styles.css b/packages/canon/css/styles.css index 9ae1899c52..9a5b19bff8 100644 --- a/packages/canon/css/styles.css +++ b/packages/canon/css/styles.css @@ -9540,6 +9540,176 @@ display: grid; } +.canon-HeaderToolbar { + z-index: 10; + padding-top: 8px; + position: sticky; + top: 0; + + &:before { + content: ""; + background-color: var(--canon-bg); + z-index: 0; + height: 16px; + position: absolute; + top: 0; + left: 0; + right: 0; + } +} + +.canon-HeaderToolbarWrapper { + z-index: 1; + background-color: var(--canon-bg-surface-1); + padding-inline: var(--canon-space-3); + border-radius: var(--canon-radius-2); + border: 1px solid var(--canon-border); + color: var(--canon-fg-primary); + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 52px; + display: flex; + position: relative; +} + +.canon-HeaderToolbarContent { + align-items: center; + gap: var(--canon-space-2); + flex-direction: row; + display: flex; +} + +.canon-HeaderToolbarName { + align-items: center; + gap: var(--canon-space-2); + font-size: var(--canon-font-size-3); + font-weight: var(--canon-font-weight-regular); + flex-direction: row; + flex-shrink: 0; + display: flex; +} + +.canon-HeaderToolbarIcon { + width: 16px; + height: 16px; + color: var(--canon-fg-primary); + + & svg { + width: 100%; + height: 100%; + } +} + +.canon-HeaderToolbarOptions { + right: var(--canon-space-2); + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.canon-HeaderBreadcrumbs { + align-items: center; + gap: var(--canon-space-2); + font-size: var(--canon-font-size-3); + font-weight: var(--canon-font-weight-regular); + flex-direction: row; + display: flex; +} + +.canon-HeaderBreadcrumb { + align-items: center; + gap: var(--canon-space-2); + flex-direction: row; + display: flex; +} + +.canon-HeaderBreadcrumbLink { + color: var(--canon-fg-secondary); + cursor: pointer; + text-decoration: none; + + &[data-active="true"] { + color: var(--canon-fg-primary); + } +} + +.canon-HeaderBreadcrumbSeparator { + width: 16px; + height: 16px; + color: var(--canon-fg-secondary); +} + +.canon-HeaderTabs { + background-color: var(--canon-bg-surface-1); + padding-inline: var(--canon-space-1); + border-radius: var(--canon-radius-2); + border: 1px solid var(--canon-border); + --active-tab-left: 0px; + --active-tab-right: 0px; + --active-tab-top: 0px; + --active-tab-bottom: 0px; + --active-tab-width: 0px; + --active-tab-height: 0px; + --hovered-tab-left: 0px; + --hovered-tab-right: 0px; + --hovered-tab-top: 0px; + --hovered-tab-bottom: 0px; + --hovered-tab-width: 0px; + --hovered-tab-height: 0px; + --hovered-tab-opacity: 0; + --hovered-transition-duration: 0s; + flex-direction: row; + align-items: center; + margin-top: 8px; + display: flex; + position: relative; +} + +.canon-HeaderTabList { + flex-direction: row; + display: flex; +} + +.canon-HeaderTab { + font-size: var(--canon-font-size-3); + color: var(--canon-fg-primary); + cursor: pointer; + z-index: 2; + height: 36px; + padding-inline: var(--canon-space-2); + justify-content: center; + align-items: center; + display: flex; + position: relative; +} + +.canon-HeaderTabActive { + content: ""; + left: calc(var(--active-tab-left) + var(--canon-space-2)); + width: calc(var(--active-tab-width) - var(--canon-space-4)); + background-color: var(--canon-fg-primary); + opacity: 1; + border-radius: 4px; + height: 1px; + transition: all .25s ease-out; + position: absolute; + bottom: -1px; +} + +.canon-HeaderTabHovered { + content: ""; + left: var(--hovered-tab-left); + top: calc(var(--hovered-tab-top) + 4px); + width: var(--hovered-tab-width); + height: calc(var(--hovered-tab-height) - 8px); + background-color: var(--canon-gray-2); + opacity: var(--hovered-tab-opacity); + transition: left var(--hovered-transition-duration) ease-out, top var(--hovered-transition-duration) ease-out, width var(--hovered-transition-duration) ease-out, height var(--hovered-transition-duration) ease-out, opacity .15s ease-out; + border-radius: 4px; + position: absolute; +} + .canon-Heading { font-family: var(--canon-font-regular); color: var(--canon-fg-primary); @@ -10265,136 +10435,6 @@ height: 1rem; } -.canon-Toolbar { - z-index: 10; - padding-top: 8px; - position: sticky; - top: 0; - - &:before { - content: ""; - background-color: var(--canon-bg); - z-index: 0; - height: 16px; - position: absolute; - top: 0; - left: 0; - right: 0; - } -} - -.canon-ToolbarContentWrapper { - z-index: 1; - background-color: var(--canon-bg-surface-1); - padding-inline: var(--canon-space-3); - border-radius: var(--canon-radius-2); - border: 1px solid var(--canon-border); - color: var(--canon-fg-primary); - flex-direction: row; - justify-content: space-between; - align-items: center; - height: 52px; - display: flex; - position: relative; -} - -.canon-ToolbarContent { - align-items: center; - gap: var(--canon-space-2); - flex-direction: row; - display: flex; -} - -.canon-ToolbarName { - align-items: center; - gap: var(--canon-space-2); - font-size: var(--canon-font-size-3); - font-weight: var(--canon-font-weight-regular); - flex-direction: row; - display: flex; -} - -.canon-ToolbarIcon { - width: 16px; - height: 16px; - color: var(--canon-fg-primary); - - & svg { - width: 100%; - height: 100%; - } -} - -.canon-ToolbarTabs { - background-color: var(--canon-bg-surface-1); - padding-inline: var(--canon-space-1); - border-radius: var(--canon-radius-2); - border: 1px solid var(--canon-border); - --active-tab-left: 0px; - --active-tab-right: 0px; - --active-tab-top: 0px; - --active-tab-bottom: 0px; - --active-tab-width: 0px; - --active-tab-height: 0px; - --hovered-tab-left: 0px; - --hovered-tab-right: 0px; - --hovered-tab-top: 0px; - --hovered-tab-bottom: 0px; - --hovered-tab-width: 0px; - --hovered-tab-height: 0px; - --hovered-tab-opacity: 0; - --hovered-transition-duration: 0s; - flex-direction: row; - align-items: center; - margin-top: 8px; - display: flex; - position: relative; -} - -.canon-ToolbarTabList { - flex-direction: row; - display: flex; -} - -.canon-ToolbarTab { - font-size: var(--canon-font-size-3); - color: var(--canon-fg-primary); - cursor: pointer; - z-index: 2; - height: 36px; - padding-inline: var(--canon-space-2); - justify-content: center; - align-items: center; - display: flex; - position: relative; -} - -.canon-ToolbarActiveIndicator { - content: ""; - left: calc(var(--active-tab-left) + var(--canon-space-2)); - width: calc(var(--active-tab-width) - var(--canon-space-4)); - background-color: var(--canon-fg-primary); - opacity: 1; - border-radius: 4px; - height: 1px; - transition: all .25s ease-out; - position: absolute; - bottom: -1px; -} - -.canon-ToolbarHoveredIndicator { - content: ""; - left: var(--hovered-tab-left); - top: calc(var(--hovered-tab-top) + 4px); - width: var(--hovered-tab-width); - height: calc(var(--hovered-tab-height) - 8px); - background-color: var(--canon-gray-2); - opacity: var(--hovered-tab-opacity); - transition: left var(--hovered-transition-duration) ease-out, top var(--hovered-transition-duration) ease-out, width var(--hovered-transition-duration) ease-out, height var(--hovered-transition-duration) ease-out, opacity .15s ease-out; - border-radius: 4px; - position: absolute; -} - .canon-TooltipPopup { box-sizing: border-box; transform-origin: var(--transform-origin); diff --git a/packages/canon/src/components/Toolbar/Tooltip.stories.tsx b/packages/canon/src/components/Header/Header.stories.tsx similarity index 89% rename from packages/canon/src/components/Toolbar/Tooltip.stories.tsx rename to packages/canon/src/components/Header/Header.stories.tsx index 5840179926..0554648bc9 100644 --- a/packages/canon/src/components/Toolbar/Tooltip.stories.tsx +++ b/packages/canon/src/components/Header/Header.stories.tsx @@ -15,18 +15,18 @@ */ import type { Meta, StoryObj, StoryFn } from '@storybook/react'; -import { Toolbar } from './Toolbar'; -import { ToolbarBreadcrumb, ToolbarOption, ToolbarTab } from './types'; +import { Header } from './Header'; +import { HeaderBreadcrumb, HeaderOption, HeaderTab } from './types'; const meta = { - title: 'Components/Toolbar', - component: Toolbar, -} satisfies Meta; + title: 'Components/Header', + component: Header, +} satisfies Meta; export default meta; type Story = StoryObj; -const tabs: ToolbarTab[] = [ +const tabs: HeaderTab[] = [ { label: 'Overview', }, @@ -44,7 +44,7 @@ const tabs: ToolbarTab[] = [ }, ]; -const breadcrumbs: ToolbarBreadcrumb[] = [ +const breadcrumbs: HeaderBreadcrumb[] = [ { label: 'Home', href: '/', @@ -59,7 +59,7 @@ const breadcrumbs: ToolbarBreadcrumb[] = [ }, ]; -const options: ToolbarOption[] = [ +const options: HeaderOption[] = [ { label: 'Settings', value: 'settings', diff --git a/packages/canon/src/components/Toolbar/Toolbar.styles.css b/packages/canon/src/components/Header/Header.styles.css similarity index 91% rename from packages/canon/src/components/Toolbar/Toolbar.styles.css rename to packages/canon/src/components/Header/Header.styles.css index ed48b008d0..76b7c6bcf4 100644 --- a/packages/canon/src/components/Toolbar/Toolbar.styles.css +++ b/packages/canon/src/components/Header/Header.styles.css @@ -14,7 +14,7 @@ * limitations under the License. */ -.canon-Toolbar { +.canon-HeaderToolbar { position: sticky; top: 0; z-index: 10; @@ -32,7 +32,7 @@ } } -.canon-ToolbarContentWrapper { +.canon-HeaderToolbarWrapper { position: relative; z-index: 1; display: flex; @@ -47,14 +47,14 @@ height: 52px; } -.canon-ToolbarContent { +.canon-HeaderToolbarContent { display: flex; flex-direction: row; align-items: center; gap: var(--canon-space-2); } -.canon-ToolbarName { +.canon-HeaderToolbarName { display: flex; flex-direction: row; align-items: center; @@ -64,7 +64,7 @@ flex-shrink: 0; } -.canon-ToolbarIcon { +.canon-HeaderToolbarIcon { width: 16px; height: 16px; color: var(--canon-fg-primary); @@ -75,7 +75,14 @@ } } -.canon-ToolbarBreadcrumbs { +.canon-HeaderToolbarOptions { + position: absolute; + right: var(--canon-space-2); + top: 50%; + transform: translateY(-50%); +} + +.canon-HeaderBreadcrumbs { display: flex; flex-direction: row; align-items: center; @@ -84,14 +91,14 @@ font-weight: var(--canon-font-weight-regular); } -.canon-ToolbarBreadcrumb { +.canon-HeaderBreadcrumb { display: flex; flex-direction: row; align-items: center; gap: var(--canon-space-2); } -.canon-ToolbarBreadcrumbLink { +.canon-HeaderBreadcrumbLink { color: var(--canon-fg-secondary); text-decoration: none; cursor: pointer; @@ -101,20 +108,13 @@ } } -.canon-ToolbarBreadcrumbSeparator { +.canon-HeaderBreadcrumbSeparator { width: 16px; height: 16px; color: var(--canon-fg-secondary); } -.canon-ToolbarOptions { - position: absolute; - right: var(--canon-space-2); - top: 50%; - transform: translateY(-50%); -} - -.canon-ToolbarTabs { +.canon-HeaderTabs { display: flex; flex-direction: row; align-items: center; @@ -143,12 +143,12 @@ --hovered-transition-duration: 0s; } -.canon-ToolbarTabList { +.canon-HeaderTabList { display: flex; flex-direction: row; } -.canon-ToolbarTab { +.canon-HeaderTab { font-size: var(--canon-font-size-3); color: var(--canon-fg-primary); height: 36px; @@ -162,7 +162,7 @@ } /* Active tab indicator */ -.canon-ToolbarActiveIndicator { +.canon-HeaderTabActive { content: ''; position: absolute; left: calc(var(--active-tab-left) + var(--canon-space-2)); @@ -176,7 +176,7 @@ } /* Hovered tab indicator */ -.canon-ToolbarHoveredIndicator { +.canon-HeaderTabHovered { content: ''; position: absolute; left: var(--hovered-tab-left); diff --git a/packages/canon/src/components/Toolbar/Toolbar.tsx b/packages/canon/src/components/Header/Header.tsx similarity index 92% rename from packages/canon/src/components/Toolbar/Toolbar.tsx rename to packages/canon/src/components/Header/Header.tsx index af958e348a..e8a42104a5 100644 --- a/packages/canon/src/components/Toolbar/Toolbar.tsx +++ b/packages/canon/src/components/Header/Header.tsx @@ -17,9 +17,9 @@ import { Tabs, TabList, Tab as AriaTab, Link } from 'react-aria-components'; import { useStyles } from '../../hooks/useStyles'; import { useId, useRef, useState, useEffect } from 'react'; -import { ToolbarTabsIndicators } from './Indicators'; +import { HeaderTabsIndicators } from './Indicators'; import { RiArrowRightSLine, RiMore2Line, RiShapesLine } from '@remixicon/react'; -import type { ToolbarProps, ToolbarTabProps } from './types'; +import type { HeaderProps, HeaderTabProps } from './types'; import { ButtonIcon } from '../ButtonIcon'; import { Menu } from '../Menu'; import { motion, useScroll, useTransform } from 'framer-motion'; @@ -29,9 +29,9 @@ import { motion, useScroll, useTransform } from 'framer-motion'; * * @public */ -export const Toolbar = (props: ToolbarProps) => { +export const Header = (props: HeaderProps) => { const { tabs, icon, name, options, breadcrumbs } = props; - const { classNames } = useStyles('Toolbar'); + const { classNames } = useStyles('Header'); const tabsRef = useRef(null); const tabRefs = useRef>(new Map()); const [hoveredKey, setHoveredKey] = useState(null); @@ -101,13 +101,12 @@ export const Toolbar = (props: ToolbarProps) => { return ( <>
-
+
-
-
{icon || }
+
+
+ {icon || } +
{name || 'Your plugin'}
{breadcrumbs && ( @@ -192,7 +191,7 @@ export const Toolbar = (props: ToolbarProps) => { ); })} - { * * @public */ -const Tab = (props: ToolbarTabProps) => { +const Tab = (props: HeaderTabProps) => { const { tab, setTabRef, setHoveredKey } = props; const id = useId(); - const { classNames } = useStyles('Toolbar'); + const { classNames } = useStyles('Header'); return ( { +export const HeaderTabsIndicators = (props: HeaderIndicatorsProps) => { const { tabRefs, tabsRef, hoveredKey, prevHoveredKey } = props; - const { classNames } = useStyles('Toolbar'); + const { classNames } = useStyles('Header'); const state = useContext(TabListStateContext); const updateCSSVariables = useCallback(() => { @@ -154,8 +154,8 @@ export const ToolbarTabsIndicators = (props: ToolbarIndicatorsProps) => { return ( <> -
-
+
+
); }; diff --git a/packages/canon/src/components/Toolbar/index.tsx b/packages/canon/src/components/Header/index.tsx similarity index 96% rename from packages/canon/src/components/Toolbar/index.tsx rename to packages/canon/src/components/Header/index.tsx index 5cc628dadc..40935319bf 100644 --- a/packages/canon/src/components/Toolbar/index.tsx +++ b/packages/canon/src/components/Header/index.tsx @@ -14,6 +14,6 @@ * limitations under the License. */ -export * from './Toolbar'; +export * from './Header'; export * from './Indicators'; export * from './types'; diff --git a/packages/canon/src/components/Toolbar/types.ts b/packages/canon/src/components/Header/types.ts similarity index 62% rename from packages/canon/src/components/Toolbar/types.ts rename to packages/canon/src/components/Header/types.ts index d2e0f336a3..b8bcf179c9 100644 --- a/packages/canon/src/components/Toolbar/types.ts +++ b/packages/canon/src/components/Header/types.ts @@ -17,66 +17,72 @@ import { MutableRefObject } from 'react'; /** - * Represents a tab item in the toolbar navigation. + * Props for the main Header component. * * @public */ -export interface ToolbarTab { +export interface HeaderProps { + icon?: React.ReactNode; + name?: string; + tabs?: HeaderTab[]; + options?: HeaderOption[]; + breadcrumbs?: HeaderBreadcrumb[]; + subNavigation?: { + name?: string; + description?: string; + tabs?: HeaderTab[]; + options?: HeaderOption[]; + }; +} + +/** + * Represents a tab item in the header navigation. + * + * @public + */ +export interface HeaderTab { label: string; href?: string; } /** - * Represents an option item in the toolbar dropdown menu. + * Represents an option item in the header dropdown menu. * * @public */ -export interface ToolbarOption { +export interface HeaderOption { label: string; value: string; onClick?: () => void; } /** - * Represents a breadcrumb item in the toolbar. + * Represents a breadcrumb item in the header. * * @public */ -export interface ToolbarBreadcrumb { +export interface HeaderBreadcrumb { label: string; href: string; } /** - * Props for the main Toolbar component. + * Props for individual header tab components. * * @public */ -export interface ToolbarProps { - icon?: React.ReactNode; - name?: string; - tabs?: ToolbarTab[]; - options?: ToolbarOption[]; - breadcrumbs?: ToolbarBreadcrumb[]; -} - -/** - * Props for individual toolbar tab components. - * - * @public - */ -export interface ToolbarTabProps { - tab: ToolbarTab; +export interface HeaderTabProps { + tab: HeaderTab; setTabRef: (key: string, element: HTMLDivElement | null) => void; setHoveredKey: (key: string | null) => void; } /** - * Props for the toolbar indicators component that handles tab highlighting and animation. + * Props for the header indicators component that handles tab highlighting and animation. * * @public */ -export interface ToolbarIndicatorsProps { +export interface HeaderIndicatorsProps { tabRefs: MutableRefObject>; tabsRef: MutableRefObject; hoveredKey: string | null; diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css index e2656be550..5fbacdc6f5 100644 --- a/packages/canon/src/css/components.css +++ b/packages/canon/src/css/components.css @@ -27,6 +27,7 @@ @import '../components/FieldLabel/FieldLabel.styles.css'; @import '../components/Flex/styles.css'; @import '../components/Grid/styles.css'; +@import '../components/Header/Header.styles.css'; @import '../components/Heading/styles.css'; @import '../components/Icon/styles.css'; @import '../components/Link/styles.css'; @@ -41,7 +42,6 @@ @import '../components/Text/styles.css'; @import '../components/TextField/TextField.styles.css'; @import '../components/SearchField/SearchField.styles.css'; -@import '../components/Toolbar/Toolbar.styles.css'; @import '../components/Tooltip/Tooltip.styles.css'; @import '../components/ScrollArea/ScrollArea.styles.css'; @import '../components/Select/Select.styles.css'; diff --git a/packages/canon/src/utils/componentDefinitions.ts b/packages/canon/src/utils/componentDefinitions.ts index 6773aa5f30..807961a33b 100644 --- a/packages/canon/src/utils/componentDefinitions.ts +++ b/packages/canon/src/utils/componentDefinitions.ts @@ -235,24 +235,23 @@ export const componentDefinitions = { disabled: [true, false] as const, }, }, - Toolbar: { + Header: { classNames: { - toolbar: 'canon-Toolbar', - toolbarContentWrapper: 'canon-ToolbarContentWrapper', - toolbarOverlay: 'canon-ToolbarOverlay', - toolbarContent: 'canon-ToolbarContent', - toolbarOptions: 'canon-ToolbarOptions', - icon: 'canon-ToolbarIcon', - name: 'canon-ToolbarName', - breadcrumbs: 'canon-ToolbarBreadcrumbs', - breadcrumb: 'canon-ToolbarBreadcrumb', - breadcrumbLink: 'canon-ToolbarBreadcrumbLink', - breadcrumbSeparator: 'canon-ToolbarBreadcrumbSeparator', - tabs: 'canon-ToolbarTabs', - tabList: 'canon-ToolbarTabList', - tab: 'canon-ToolbarTab', - activeIndicator: 'canon-ToolbarActiveIndicator', - hoveredIndicator: 'canon-ToolbarHoveredIndicator', + toolbar: 'canon-HeaderToolbar', + toolbarWrapper: 'canon-HeaderToolbarWrapper', + toolbarContent: 'canon-HeaderToolbarContent', + toolbarOptions: 'canon-HeaderToolbarOptions', + toolbarIcon: 'canon-HeaderToolbarIcon', + toolbarName: 'canon-HeaderToolbarName', + breadcrumbs: 'canon-HeaderBreadcrumbs', + breadcrumb: 'canon-HeaderBreadcrumb', + breadcrumbLink: 'canon-HeaderBreadcrumbLink', + breadcrumbSeparator: 'canon-HeaderBreadcrumbSeparator', + tabs: 'canon-HeaderTabs', + tabList: 'canon-HeaderTabList', + tab: 'canon-HeaderTab', + tabActive: 'canon-HeaderTabActive', + tabHovered: 'canon-HeaderTabHovered', }, }, Tooltip: {