Skip to content

Commit

Permalink
feat(Guidebanner): convert to .tsx (#5321)
Browse files Browse the repository at this point in the history
* fix: convert to tsx

* fix: as per review
  • Loading branch information
paul-balchin-ibm authored May 23, 2024
1 parent d54fb50 commit bd1ace3
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Copyright IBM Corp. 2023, 2023
* Copyright IBM Corp. 2023, 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

// Import portions of React that are needed.
import React, { useRef, useState } from 'react';
import React, { ReactNode, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { blue90, purple70 } from '@carbon/colors';
Expand All @@ -20,6 +20,60 @@ import { pkg } from '../../settings';
const blockClass = `${pkg.prefix}--guidebanner`;
const componentName = 'Guidebanner';

interface GuidebannerProps {
/**
* Provide the contents of the Guidebanner.
* One or more GuidebannerElement components are required.
*/
children: ReactNode;
/**
* Provide an optional class to be applied to the containing node.
*/
className?: string;
/**
* Tooltip text and aria label for the Close button icon.
*/
closeIconDescription?: string;
/**
* Text label for the Collapse button.
*/
collapseButtonLabel?: string;
/**
* When true, the Guidebanner will initialize in a collapsed state,
* showing the title and the Expand button.
*
* When expanded, it will show the GuidebannerElement child components and the Collapse button.
*/
collapsible?: boolean;
/**
* Text label for the Expand button.
*/
expandButtonLabel?: string;
/**
* Tooltip text and aria label for the Next button icon.
*/
nextIconDescription?: string;
/**
* If defined, a Close button will render in the top-right corner and a
* callback function will be triggered when button is clicked.
*/
onClose?: () => void;
/**
* Tooltip text and aria label for the Back button icon.
*/
previousIconDescription?: string;
/**
* Title text.
*/
title: string;
/**
* If true, insert 1 rem of "space" on the left of the component.
* This will allow the component's content to line up with other
* content on the page under special circumstances.
*/
withLeftGutter?: boolean;
}

const defaults = {
collapsible: false,
withLeftGutter: false,
Expand All @@ -35,7 +89,7 @@ const defaults = {
* The guide banner sits at the top of a page, or page-level tab,
* to introduce foundational concepts related to the page's content.
*/
export let Guidebanner = React.forwardRef(
export let Guidebanner = React.forwardRef<HTMLDivElement, GuidebannerProps>(
(
{
children,
Expand All @@ -54,8 +108,8 @@ export let Guidebanner = React.forwardRef(
},
ref
) => {
const scrollRef = useRef();
const toggleRef = useRef();
const scrollRef = useRef<any>(null);
const toggleRef = useRef<HTMLDivElement>(null);
const [scrollPosition, setScrollPosition] = useState(0);
const [showNavigation, setShowNavigation] = useState(false);
const [isCollapsed, setIsCollapsed] = useState(collapsible ? true : false);
Expand All @@ -67,6 +121,7 @@ export let Guidebanner = React.forwardRef(
return (
<div
{...rest}
aria-expanded={!isCollapsed}
className={cx(
blockClass,
className,
Expand Down Expand Up @@ -106,7 +161,6 @@ export let Guidebanner = React.forwardRef(
className={`${blockClass}__toggle-button`}
onClick={handleClickToggle}
ref={toggleRef}
aria-expanded={!isCollapsed}
>
{isCollapsed ? expandButtonLabel : collapseButtonLabel}
</Button>
Expand Down Expand Up @@ -201,9 +255,10 @@ Guidebanner.propTypes = {
}
React.Children.forEach(prop, (child) => {
if (child.type.displayName !== 'GuidebannerElement') {
// If not GuidebannerElement, then show:
// React component name(child.type?.name) or
// HTML element name(child.type).
// If child element is not `GuidebannerElement`, then show:
// Carbon Products component's `displayName` (child.type.displayName) or
// React component's `name` (child.type.name) or
// HTML element's tag name (child.type).
error = new Error(
`\`Guidebanner\` only accepts children of type \`GuidebannerElement\`, found \`${
child.type?.displayName || child.type?.name || child.type
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Copyright IBM Corp. 2023, 2023
* Copyright IBM Corp. 2023, 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

// Import portions of React that are needed.
import React from 'react';
import React, { ReactNode } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { getDevtoolsProps } from '../../global/js/utils/devtools';
Expand All @@ -16,29 +16,47 @@ import { pkg } from '../../settings';
const blockClass = `${pkg.prefix}--guidebanner__element`;
const componentName = 'GuidebannerElement';

interface GuidebannerElementProps {
/**
* An optional button can be rendered below the description.
* This can be a link, button, Coachmark button, etc.
*/
button?: ReactNode;
/**
* Provide an optional class to be applied to the containing node.
*/
className?: string;
/**
* The description of the element.
*/
description: ReactNode;
/**
* The title of the element.
*/
title?: string;
}

/**
* The GuidebannerElement is a required child component of the Guidebanner,
* and acts as a container for a CarouselItem.
*/
export let GuidebannerElement = ({
button,
className,
description,
title,
...rest
}) => {
export let GuidebannerElement = React.forwardRef<
HTMLDivElement,
GuidebannerElementProps
>(({ button, className, description, title, ...rest }, ref) => {
return (
<div
{...rest}
className={cx(blockClass, className)}
ref={ref}
{...getDevtoolsProps(componentName)}
>
{title && <h2 className={`${blockClass}-title`}>{title}</h2>}
{description && <p className={`${blockClass}-content`}>{description}</p>}
{button && <div className={`${blockClass}-buttons`}>{button}</div>}
</div>
);
};
});

// Return a placeholder if not released and not enabled by feature flag
GuidebannerElement = pkg.checkComponentEnabled(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Copyright IBM Corp. 2023, 2023
* Copyright IBM Corp. 2023, 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

// Import portions of React that are needed.
import React from 'react';
import React, { ReactNode } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { Button } from '@carbon/react';
Expand All @@ -18,23 +18,73 @@ import { pkg } from '../../settings';
const blockClass = `${pkg.prefix}--guidebanner__element-button`;
const componentName = 'GuidebannerElementButton';

interface GuidebannerElementButtonProps {
/**
* Provide the contents of the GuidebannerElementLink.
*/
children: ReactNode;

/**
* Provide an optional class to be applied to the containing node.
*/
className?: string;

/**
* Provide a description for the icon.
*/
iconDescription?: string;

/**
* If type is "primary", then return a tertiary button with the "crossroads" icon,
* else return a ghost button.
*/
type?: string;
}

const defaults = {
iconDescription: 'Crossroads',
};

/**
* One of two buttons styled specifically for the GuidebannerElement.
*/
export let GuidebannerElementButton = ({
children,
className,
type,
...rest
}) => {
if (type === 'primary') {
export let GuidebannerElementButton = React.forwardRef<
Button,
GuidebannerElementButtonProps
>(
(
{
children,
className,
iconDescription = defaults.iconDescription,
type,
...rest
}: GuidebannerElementButtonProps,
ref
) => {
if (type === 'primary') {
return (
<Button
{...rest}
className={cx(blockClass, className)}
iconDescription={iconDescription}
kind="tertiary"
ref={ref}
renderIcon={() => <Crossroads size={16} />}
role="button"
size="md"
{...getDevtoolsProps(componentName)}
>
{children}
</Button>
);
}

return (
<Button
{...rest}
className={cx(blockClass, className)}
iconDescription={'Crossroads'}
kind="tertiary"
renderIcon={() => <Crossroads size={16} />}
kind="ghost"
role="button"
size="md"
{...getDevtoolsProps(componentName)}
Expand All @@ -43,20 +93,7 @@ export let GuidebannerElementButton = ({
</Button>
);
}

return (
<Button
{...rest}
className={cx(blockClass, className)}
kind="ghost"
role="button"
size="md"
{...getDevtoolsProps(componentName)}
>
{children}
</Button>
);
};
);

// Return a placeholder if not released and not enabled by feature flag
GuidebannerElementButton = pkg.checkComponentEnabled(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Copyright IBM Corp. 2023, 2023
* Copyright IBM Corp. 2023, 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

// Import portions of React that are needed.
import React from 'react';
import React, { ReactNode } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { Link } from '@carbon/react';
Expand All @@ -17,23 +17,39 @@ import { pkg } from '../../settings';
const blockClass = `${pkg.prefix}--guidebanner__element-link`;
const componentName = 'GuidebannerElementLink';

interface GuidebannerElementLinkProps {
/**
* Provide the contents of the GuidebannerElementLink.
*/
children: ReactNode;

/**
* Provide an optional class to be applied to the containing node.
*/
className?: string;
}

/**
* A link styled specifically for the GuidebannerElement.
*/
export let GuidebannerElementLink = ({ children, className, ...rest }) => {
export let GuidebannerElementLink = React.forwardRef<
Link,
GuidebannerElementLinkProps
>(({ children, className, ...rest }: GuidebannerElementLinkProps, ref) => {
return (
<Link
{...rest}
className={cx(blockClass, className)}
kind="ghost"
ref={ref}
role="link"
size="md"
{...getDevtoolsProps(componentName)}
>
{children}
</Link>
);
};
});

// Return a placeholder if not released and not enabled by feature flag
GuidebannerElementLink = pkg.checkComponentEnabled(
Expand Down

0 comments on commit bd1ace3

Please sign in to comment.