Migrate PluginHeader component from useStyles to useDefinition
Signed-off-by: Johan Persson <johanopersson@gmail.com>
This commit is contained in:
@@ -79,8 +79,8 @@ These are the simplest migrations — single component, no bg, no utility props.
|
||||
### Batch 5: Multi-sub-component directories
|
||||
|
||||
- [x] **Task 21: Migrate Dialog** — Multiple sub-components (Dialog, DialogHeader, DialogBody, DialogFooter). Split monolithic definition into 4 per-sub-component definitions. Used `classNameTarget: 'dialog'` for Dialog since className targets inner RADialog, not Modal overlay. Added `style` to DialogOwnProps for manual merging with CSS custom properties. Added DialogFooterProps/OwnProps (was inline type). DialogTrigger unchanged (no useStyles usage).
|
||||
- [ ] **Task 22: Migrate HeaderPage** — Multiple sub-components (HeaderPage, HeaderPageContent). See `HeaderPage/definition.ts` and `HeaderPage/HeaderPage.tsx`.
|
||||
- [ ] **Task 23: Migrate PluginHeader** — Multiple sub-components (PluginHeader, PluginHeaderToolbar). See `PluginHeader/definition.ts` and `PluginHeader/PluginHeader.tsx` + `PluginHeaderToolbar.tsx`.
|
||||
- [x] **Task 22: Migrate HeaderPage** — Single component (not multi-sub-component as originally described — `content`, `breadcrumbs`, `tabsWrapper`, `controls` are just classNames for inner divs). No bg, no dataAttributes, no utilityProps. See `HeaderPage/definition.ts` and `HeaderPage/HeaderPage.tsx`.
|
||||
- [x] **Task 23: Migrate PluginHeader** — Two sub-components (PluginHeader, PluginHeaderToolbar) sharing one old definition, split into two `defineComponent` calls following the Dialog pattern. Toolbar definition is `@internal` and not exported. No bg, no utilityProps, no dataAttributes. Manual `data-has-tabs` preserved as-is. Toolbar classNames removed from public `PluginHeaderDefinition` (breaking API surface change to be documented in Task 33 changeset).
|
||||
- [ ] **Task 24: Migrate RadioGroup** — Multiple sub-components (RadioGroup, Radio). See `RadioGroup/definition.ts` and `RadioGroup/RadioGroup.tsx`.
|
||||
- [ ] **Task 25: Migrate Select** — Multiple sub-components (Select, SelectContent, SelectTrigger, SelectListBox). See `Select/definition.ts` and `Select/Select.tsx` + sub-files.
|
||||
- [ ] **Task 26: Migrate Table** — Many sub-components (TableRoot, TableHeader, TableBody, Row, Column, Cell, CellText, CellProfile). See `Table/definition.ts` and multiple .tsx files.
|
||||
@@ -97,7 +97,7 @@ These are the simplest migrations — single component, no bg, no utility props.
|
||||
|
||||
## Discoveries / Notes
|
||||
|
||||
- 20 of 31 component tasks complete (~65%), plus 3 cleanup tasks remaining. 26 unique components migrated.
|
||||
- 22 of 31 component tasks complete (~71%), plus 3 cleanup tasks remaining. 28 unique components migrated (PluginHeader + PluginHeaderToolbar).
|
||||
- Only 3 sub-components need bg: 'provider' (Flex, GridRoot, GridItem). No unmigrated components use useBgConsumer.
|
||||
- InternalLinkProvider is a context provider, not a styled component — no migration needed.
|
||||
- useStyles.ts already imports helpers from useDefinition (resolveResponsiveValue, processUtilityProps), confirming shared infrastructure.
|
||||
|
||||
@@ -1743,20 +1743,26 @@ export const PluginHeader: (props: PluginHeaderProps) => JSX_2.Element;
|
||||
|
||||
// @public
|
||||
export const PluginHeaderDefinition: {
|
||||
readonly styles: {
|
||||
readonly [key: string]: string;
|
||||
};
|
||||
readonly classNames: {
|
||||
readonly root: 'bui-PluginHeader';
|
||||
readonly toolbar: 'bui-PluginHeaderToolbar';
|
||||
readonly toolbarWrapper: 'bui-PluginHeaderToolbarWrapper';
|
||||
readonly toolbarContent: 'bui-PluginHeaderToolbarContent';
|
||||
readonly toolbarControls: 'bui-PluginHeaderToolbarControls';
|
||||
readonly toolbarIcon: 'bui-PluginHeaderToolbarIcon';
|
||||
readonly toolbarName: 'bui-PluginHeaderToolbarName';
|
||||
readonly tabsWrapper: 'bui-PluginHeaderTabsWrapper';
|
||||
};
|
||||
readonly propDefs: {
|
||||
readonly icon: {};
|
||||
readonly title: {};
|
||||
readonly titleLink: {};
|
||||
readonly customActions: {};
|
||||
readonly tabs: {};
|
||||
readonly onTabSelectionChange: {};
|
||||
readonly className: {};
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface PluginHeaderProps {
|
||||
export interface PluginHeaderOwnProps {
|
||||
// (undocumented)
|
||||
className?: string;
|
||||
// (undocumented)
|
||||
@@ -1773,6 +1779,9 @@ export interface PluginHeaderProps {
|
||||
titleLink?: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface PluginHeaderProps extends PluginHeaderOwnProps {}
|
||||
|
||||
// @public
|
||||
export const Popover: ForwardRefExoticComponent<
|
||||
PopoverProps & RefAttributes<HTMLDivElement>
|
||||
|
||||
@@ -17,13 +17,11 @@
|
||||
import type { PluginHeaderProps } from './types';
|
||||
import { PluginHeaderToolbar } from './PluginHeaderToolbar';
|
||||
import { Tabs, TabList, Tab } from '../Tabs';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
import { useDefinition } from '../../hooks/useDefinition';
|
||||
import { PluginHeaderDefinition } from './definition';
|
||||
import { type NavigateOptions } from 'react-router-dom';
|
||||
import { useRef } from 'react';
|
||||
import { useIsomorphicLayoutEffect } from '../../hooks/useIsomorphicLayoutEffect';
|
||||
import styles from './PluginHeader.module.css';
|
||||
import clsx from 'clsx';
|
||||
|
||||
declare module 'react-aria-components' {
|
||||
interface RouterConfig {
|
||||
@@ -38,16 +36,16 @@ declare module 'react-aria-components' {
|
||||
* @public
|
||||
*/
|
||||
export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
const { classNames, cleanedProps } = useStyles(PluginHeaderDefinition, props);
|
||||
const { ownProps } = useDefinition(PluginHeaderDefinition, props);
|
||||
const {
|
||||
className,
|
||||
classes,
|
||||
tabs,
|
||||
icon,
|
||||
title,
|
||||
titleLink,
|
||||
customActions,
|
||||
onTabSelectionChange,
|
||||
} = cleanedProps;
|
||||
} = ownProps;
|
||||
|
||||
const hasTabs = tabs && tabs.length > 0;
|
||||
const headerRef = useRef<HTMLElement>(null);
|
||||
@@ -85,10 +83,7 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header
|
||||
ref={headerRef}
|
||||
className={clsx(classNames.root, styles[classNames.root], className)}
|
||||
>
|
||||
<header ref={headerRef} className={classes.root}>
|
||||
<PluginHeaderToolbar
|
||||
icon={icon}
|
||||
title={title}
|
||||
@@ -97,12 +92,7 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
hasTabs={hasTabs}
|
||||
/>
|
||||
{tabs && (
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.tabsWrapper,
|
||||
styles[classNames.tabsWrapper],
|
||||
)}
|
||||
>
|
||||
<div className={classes.tabsWrapper}>
|
||||
<Tabs onSelectionChange={onTabSelectionChange}>
|
||||
<TabList>
|
||||
{tabs?.map(tab => (
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
|
||||
import { Link } from 'react-aria-components';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
import { PluginHeaderDefinition } from './definition';
|
||||
import { useDefinition } from '../../hooks/useDefinition';
|
||||
import { PluginHeaderToolbarDefinition } from './definition';
|
||||
import { useRef } from 'react';
|
||||
import { RiShapesLine } from '@remixicon/react';
|
||||
import type { PluginHeaderToolbarProps } from './types';
|
||||
import { Text } from '../Text';
|
||||
import styles from './PluginHeader.module.css';
|
||||
import clsx from 'clsx';
|
||||
|
||||
/**
|
||||
* A component that renders the toolbar section of a plugin header.
|
||||
@@ -30,9 +28,8 @@ import clsx from 'clsx';
|
||||
* @internal
|
||||
*/
|
||||
export const PluginHeaderToolbar = (props: PluginHeaderToolbarProps) => {
|
||||
const { classNames, cleanedProps } = useStyles(PluginHeaderDefinition, props);
|
||||
const { className, icon, title, titleLink, customActions, hasTabs } =
|
||||
cleanedProps;
|
||||
const { ownProps } = useDefinition(PluginHeaderToolbarDefinition, props);
|
||||
const { classes, icon, title, titleLink, customActions, hasTabs } = ownProps;
|
||||
|
||||
// Refs for collision detection
|
||||
const toolbarWrapperRef = useRef<HTMLDivElement>(null);
|
||||
@@ -41,68 +38,26 @@ export const PluginHeaderToolbar = (props: PluginHeaderToolbarProps) => {
|
||||
|
||||
const titleContent = (
|
||||
<>
|
||||
<div
|
||||
className={clsx(classNames.toolbarIcon, styles[classNames.toolbarIcon])}
|
||||
>
|
||||
{icon || <RiShapesLine />}
|
||||
</div>
|
||||
<div className={classes.icon}>{icon || <RiShapesLine />}</div>
|
||||
<Text variant="body-medium">{title || 'Your plugin'}</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.toolbar,
|
||||
styles[classNames.toolbar],
|
||||
className,
|
||||
)}
|
||||
data-has-tabs={hasTabs}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.toolbarWrapper,
|
||||
styles[classNames.toolbarWrapper],
|
||||
)}
|
||||
ref={toolbarWrapperRef}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.toolbarContent,
|
||||
styles[classNames.toolbarContent],
|
||||
)}
|
||||
ref={toolbarContentRef}
|
||||
>
|
||||
<div className={classes.root} data-has-tabs={hasTabs}>
|
||||
<div className={classes.wrapper} ref={toolbarWrapperRef}>
|
||||
<div className={classes.content} ref={toolbarContentRef}>
|
||||
<Text as="h1" variant="body-medium">
|
||||
{titleLink ? (
|
||||
<Link
|
||||
className={clsx(
|
||||
classNames.toolbarName,
|
||||
styles[classNames.toolbarName],
|
||||
)}
|
||||
href={titleLink}
|
||||
>
|
||||
<Link className={classes.name} href={titleLink}>
|
||||
{titleContent}
|
||||
</Link>
|
||||
) : (
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.toolbarName,
|
||||
styles[classNames.toolbarName],
|
||||
)}
|
||||
>
|
||||
{titleContent}
|
||||
</div>
|
||||
<div className={classes.name}>{titleContent}</div>
|
||||
)}
|
||||
</Text>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.toolbarControls,
|
||||
styles[classNames.toolbarControls],
|
||||
)}
|
||||
ref={toolbarControlsRef}
|
||||
>
|
||||
<div className={classes.controls} ref={toolbarControlsRef}>
|
||||
{customActions}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,21 +14,55 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { ComponentDefinition } from '../../types';
|
||||
import { defineComponent } from '../../hooks/useDefinition';
|
||||
import type {
|
||||
PluginHeaderOwnProps,
|
||||
PluginHeaderToolbarOwnProps,
|
||||
} from './types';
|
||||
import styles from './PluginHeader.module.css';
|
||||
|
||||
/**
|
||||
* Component definition for PluginHeader
|
||||
* @public
|
||||
*/
|
||||
export const PluginHeaderDefinition = {
|
||||
export const PluginHeaderDefinition = defineComponent<PluginHeaderOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-PluginHeader',
|
||||
toolbar: 'bui-PluginHeaderToolbar',
|
||||
toolbarWrapper: 'bui-PluginHeaderToolbarWrapper',
|
||||
toolbarContent: 'bui-PluginHeaderToolbarContent',
|
||||
toolbarControls: 'bui-PluginHeaderToolbarControls',
|
||||
toolbarIcon: 'bui-PluginHeaderToolbarIcon',
|
||||
toolbarName: 'bui-PluginHeaderToolbarName',
|
||||
tabsWrapper: 'bui-PluginHeaderTabsWrapper',
|
||||
},
|
||||
} as const satisfies ComponentDefinition;
|
||||
propDefs: {
|
||||
icon: {},
|
||||
title: {},
|
||||
titleLink: {},
|
||||
customActions: {},
|
||||
tabs: {},
|
||||
onTabSelectionChange: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Component definition for PluginHeaderToolbar
|
||||
* @internal
|
||||
*/
|
||||
export const PluginHeaderToolbarDefinition =
|
||||
defineComponent<PluginHeaderToolbarOwnProps>()({
|
||||
styles,
|
||||
classNames: {
|
||||
root: 'bui-PluginHeaderToolbar',
|
||||
wrapper: 'bui-PluginHeaderToolbarWrapper',
|
||||
content: 'bui-PluginHeaderToolbarContent',
|
||||
controls: 'bui-PluginHeaderToolbarControls',
|
||||
icon: 'bui-PluginHeaderToolbarIcon',
|
||||
name: 'bui-PluginHeaderToolbarName',
|
||||
},
|
||||
propDefs: {
|
||||
icon: {},
|
||||
title: {},
|
||||
titleLink: {},
|
||||
customActions: {},
|
||||
hasTabs: {},
|
||||
className: {},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -16,4 +16,8 @@
|
||||
|
||||
export { PluginHeader } from './PluginHeader';
|
||||
export { PluginHeaderDefinition } from './definition';
|
||||
export type { PluginHeaderProps, HeaderTab } from './types';
|
||||
export type {
|
||||
PluginHeaderOwnProps,
|
||||
PluginHeaderProps,
|
||||
HeaderTab,
|
||||
} from './types';
|
||||
|
||||
@@ -18,11 +18,11 @@ import { TabsProps } from 'react-aria-components';
|
||||
import { TabMatchStrategy } from '../Tabs';
|
||||
|
||||
/**
|
||||
* Props for the {@link PluginHeader} component.
|
||||
* Own props for the {@link PluginHeader} component.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface PluginHeaderProps {
|
||||
export interface PluginHeaderOwnProps {
|
||||
icon?: React.ReactNode;
|
||||
title?: string;
|
||||
titleLink?: string;
|
||||
@@ -32,6 +32,13 @@ export interface PluginHeaderProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for the {@link PluginHeader} component.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface PluginHeaderProps extends PluginHeaderOwnProps {}
|
||||
|
||||
/**
|
||||
* Represents a tab item in the header navigation.
|
||||
*
|
||||
@@ -49,16 +56,23 @@ export interface HeaderTab {
|
||||
matchStrategy?: TabMatchStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Own props for the PluginHeaderToolbar component.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface PluginHeaderToolbarOwnProps {
|
||||
icon?: PluginHeaderOwnProps['icon'];
|
||||
title?: PluginHeaderOwnProps['title'];
|
||||
titleLink?: PluginHeaderOwnProps['titleLink'];
|
||||
customActions?: PluginHeaderOwnProps['customActions'];
|
||||
hasTabs?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for the PluginHeaderToolbar component.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface PluginHeaderToolbarProps {
|
||||
icon?: PluginHeaderProps['icon'];
|
||||
title?: PluginHeaderProps['title'];
|
||||
titleLink?: PluginHeaderProps['titleLink'];
|
||||
customActions?: PluginHeaderProps['customActions'];
|
||||
hasTabs?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
export interface PluginHeaderToolbarProps extends PluginHeaderToolbarOwnProps {}
|
||||
|
||||
Reference in New Issue
Block a user