From 3b8e15389325046d9b44d35c82abc69ba19b2194 Mon Sep 17 00:00:00 2001 From: Pavel Klibani <pavel@techloop.io> Date: Fri, 2 Feb 2024 15:43:42 +0100 Subject: [PATCH 1/5] Fix(web-react): Add forwardRef to Icon components - Icon component now accept forwarded ref and can be used as TooltipTrigger --- .../web-react/src/components/Icon/Icon.tsx | 10 ++++++++-- .../src/components/Icon/demo/Icon.tsx | 18 ------------------ .../src/components/Icon/demo/index.tsx | 2 +- 3 files changed, 9 insertions(+), 21 deletions(-) delete mode 100644 packages/web-react/src/components/Icon/demo/Icon.tsx diff --git a/packages/web-react/src/components/Icon/Icon.tsx b/packages/web-react/src/components/Icon/Icon.tsx index 0b216cc941..cd5a7a2154 100644 --- a/packages/web-react/src/components/Icon/Icon.tsx +++ b/packages/web-react/src/components/Icon/Icon.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ForwardedRef, forwardRef } from 'react'; import { warning } from '../../common/utilities'; import { useIcon, useStyleProps } from '../../hooks'; import { IconProps } from '../../types'; @@ -10,7 +10,9 @@ const defaultProps = { boxSize: 24, }; -export const Icon = (props: IconProps) => { +/* We need an exception for components exported with forwardRef */ +/* eslint no-underscore-dangle: ['error', { allow: ['_Icon'] }] */ +export const _Icon = (props: IconProps, ref: ForwardedRef<SVGSVGElement>) => { const { boxSize, name, title, ariaHidden, ...restProps } = props; let icon = useIcon(name); const { styleProps, props: otherProps } = useStyleProps(restProps); @@ -41,6 +43,7 @@ export const Icon = (props: IconProps) => { {...otherProps} {...styleProps} className={styleProps.className} + ref={ref} > {/* @ts-expect-error TS2349: This expression is not callable. Type 'never' has no call signatures. */} {htmlParser(icon)} @@ -64,11 +67,14 @@ export const Icon = (props: IconProps) => { {...otherProps} {...styleProps} className={styleProps.className} + ref={ref} /> </NoSsr> ); }; +export const Icon = forwardRef<SVGSVGElement, IconProps>(_Icon); + Icon.defaultProps = defaultProps; export default Icon; diff --git a/packages/web-react/src/components/Icon/demo/Icon.tsx b/packages/web-react/src/components/Icon/demo/Icon.tsx deleted file mode 100644 index 15529ee778..0000000000 --- a/packages/web-react/src/components/Icon/demo/Icon.tsx +++ /dev/null @@ -1,18 +0,0 @@ -// Because there is no `dist` directory during the CI run -/* eslint-disable import/no-extraneous-dependencies, import/extensions, import/no-unresolved */ -import React from 'react'; -import { ComponentStory } from '@storybook/react'; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore: No declaration file -import icons from '@lmc-eu/spirit-icons/dist/icons'; -import { IconsProvider } from '../../../context'; -import Icon from '../Icon'; -import { IconProps } from '../../../types'; - -const Story: ComponentStory<typeof Icon> = (args: IconProps) => ( - <IconsProvider value={icons}> - <Icon {...args} /> - </IconsProvider> -); - -export default Story; diff --git a/packages/web-react/src/components/Icon/demo/index.tsx b/packages/web-react/src/components/Icon/demo/index.tsx index 181c12f287..f42026ccc9 100644 --- a/packages/web-react/src/components/Icon/demo/index.tsx +++ b/packages/web-react/src/components/Icon/demo/index.tsx @@ -7,7 +7,7 @@ import ReactDOM from 'react-dom/client'; import icons from '@lmc-eu/spirit-icons/dist/icons'; import { IconsProvider } from '../../../context'; import DocsSection from '../../../../docs/DocsSections'; -import Icon from './Icon'; +import Icon from '../Icon'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <React.StrictMode> From f1165369b1c696e43ac1b66b6d94553e7b9d7535 Mon Sep 17 00:00:00 2001 From: Pavel Klibani <pavel@techloop.io> Date: Fri, 2 Feb 2024 15:45:07 +0100 Subject: [PATCH 2/5] Fix(web-react): TooltipTrigger props update - elementType can be now self closing (fe. Icon) - accepting props from elementType components --- .../web-react/src/components/Tooltip/TooltipTrigger.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/web-react/src/components/Tooltip/TooltipTrigger.tsx b/packages/web-react/src/components/Tooltip/TooltipTrigger.tsx index ceea9507b7..40806fe2cd 100644 --- a/packages/web-react/src/components/Tooltip/TooltipTrigger.tsx +++ b/packages/web-react/src/components/Tooltip/TooltipTrigger.tsx @@ -1,11 +1,11 @@ import React, { ElementType, ReactNode } from 'react'; import { useStyleProps } from '../../hooks'; -import { StyleProps } from '../../types'; +import { StyleProps, TransferProps } from '../../types'; import { useTooltipContext } from './TooltipContext'; -interface TooltipTriggerProps extends StyleProps { +interface TooltipTriggerProps extends StyleProps, TransferProps { elementType?: ElementType | string; - children: string | ReactNode | ((props: { isOpen: boolean }) => React.ReactNode); + children?: string | ReactNode | ((props: { isOpen: boolean }) => React.ReactNode); } const TooltipTrigger = (props: TooltipTriggerProps) => { @@ -25,6 +25,7 @@ const TooltipTrigger = (props: TooltipTriggerProps) => { TooltipTrigger.defaultProps = { elementType: 'button', + children: null, }; export default TooltipTrigger; From 84b227df8ee733ce065035496f4996701ecf29ad Mon Sep 17 00:00:00 2001 From: Pavel Klibani <pavel@techloop.io> Date: Fri, 2 Feb 2024 15:47:24 +0100 Subject: [PATCH 3/5] Docs(web-react): Add demo with Tooltip on Icon cmp - New demo with tooltip on Icon component --- .../TooltipModern/demo/TooltipIcon.tsx | 35 +++++++++++++++++++ .../components/TooltipModern/demo/index.tsx | 4 +++ 2 files changed, 39 insertions(+) create mode 100644 packages/web-react/src/components/TooltipModern/demo/TooltipIcon.tsx diff --git a/packages/web-react/src/components/TooltipModern/demo/TooltipIcon.tsx b/packages/web-react/src/components/TooltipModern/demo/TooltipIcon.tsx new file mode 100644 index 0000000000..8c95877679 --- /dev/null +++ b/packages/web-react/src/components/TooltipModern/demo/TooltipIcon.tsx @@ -0,0 +1,35 @@ +import React, { useState } from 'react'; +import { Icon } from '../../Icon'; +import { TooltipModern, TooltipPopover, TooltipTrigger } from '../../Tooltip'; + +const TooltipIcon = () => { + const [openIcon, setOpenIcon] = useState(false); + + return ( + <div className="spirit-feature-tooltip-enable-data-placement"> + <p> + Click on the icon on the right to view the tooltip{' '} + <TooltipModern + id="tooltip-example-with-icon" + isOpen={openIcon} + onToggle={setOpenIcon} + placement="right" + flipFallbackPlacements={['top-start', 'bottom-start', 'left']} + UNSAFE_className="d-inline-block" + isDismissible + > + <TooltipTrigger + elementType={Icon} + name="info" + boxSize={16} + UNSAFE_className="d-inline-block" + marginBottom="space-200" + /> + <TooltipPopover>Close me</TooltipPopover> + </TooltipModern> + </p> + </div> + ); +}; + +export default TooltipIcon; diff --git a/packages/web-react/src/components/TooltipModern/demo/index.tsx b/packages/web-react/src/components/TooltipModern/demo/index.tsx index 5a8bbd4cf8..f9711f85a6 100644 --- a/packages/web-react/src/components/TooltipModern/demo/index.tsx +++ b/packages/web-react/src/components/TooltipModern/demo/index.tsx @@ -13,6 +13,7 @@ import TooltipDismissibleViaJS from './TooltipDismissibleViaJS'; import TooltipOnHover from './TooltipOnHover'; import TooltipPlacements from './TooltipPlacements'; import TooltipWithFloatingUI from './TooltipWithFloatingUI'; +import TooltipIcon from './TooltipIcon'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <React.StrictMode> @@ -32,6 +33,9 @@ ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <DocsSection title="Dismissible Tooltip via JS API and Floating UI"> <TooltipDismissibleViaJS /> </DocsSection> + <DocsSection title="Tooltip on Icon Component"> + <TooltipIcon /> + </DocsSection> <DocsSection title="Advanced Floating Functionality" stackAlignment="stretch"> <TooltipWithFloatingUI /> </DocsSection> From a3e338c3b33911bcc250caa538cfe449c7f39ffa Mon Sep 17 00:00:00 2001 From: Pavel Klibani <pavel@techloop.io> Date: Fri, 2 Feb 2024 15:48:35 +0100 Subject: [PATCH 4/5] Docs(web-twig): Add demo with Tooltip on Icon cmp - New demo with tooltip on Icon component --- .../components/Tooltip/Tooltip.stories.twig | 4 ++++ .../Tooltip/stories/TooltipIcon.twig | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 packages/web-twig/src/Resources/components/Tooltip/stories/TooltipIcon.twig diff --git a/packages/web-twig/src/Resources/components/Tooltip/Tooltip.stories.twig b/packages/web-twig/src/Resources/components/Tooltip/Tooltip.stories.twig index b703a709ea..7962597faf 100644 --- a/packages/web-twig/src/Resources/components/Tooltip/Tooltip.stories.twig +++ b/packages/web-twig/src/Resources/components/Tooltip/Tooltip.stories.twig @@ -30,6 +30,10 @@ {% include '@components/Tooltip/stories/TooltipDismissibleViaJS.twig' %} </DocsSection> + <DocsSection title="Tooltip on Icon Component"> + {% include '@components/Tooltip/stories/TooltipIcon.twig' %} + </DocsSection> + <DocsSection title="Advanced Floating Functionality"> {% include '@components/Tooltip/stories/TooltipFloatingUI.twig' %} </DocsSection> diff --git a/packages/web-twig/src/Resources/components/Tooltip/stories/TooltipIcon.twig b/packages/web-twig/src/Resources/components/Tooltip/stories/TooltipIcon.twig new file mode 100644 index 0000000000..88ba2c215e --- /dev/null +++ b/packages/web-twig/src/Resources/components/Tooltip/stories/TooltipIcon.twig @@ -0,0 +1,24 @@ +<span> + Click on the icon on the right to view the tooltip + <TooltipWrapper UNSAFE_className="spirit-feature-tooltip-enable-data-placement d-inline-block"> + <Icon + id="button-example-with-icon" + name="info" + boxSize="16" + marginBottom="space-200" + aria-describedby="tooltip-example-with-icon" + data-spirit-toggle="tooltip" + data-spirit-target="#tooltip-example-with-icon" + /> + <TooltipPopover + id="tooltip-example-with-icon" + UNSAFE_className="is-hidden" + enableControlledPlacement + placement="right" + flipFallbackPlacements="top-start, top-bottom, left" + isDismissible + > + Close me + </TooltipPopov> + </TooltipWrapper> +</span> \ No newline at end of file From 48da1b2c200d257778aa245401963a4d7f70e80e Mon Sep 17 00:00:00 2001 From: Pavel Klibani <pavel@techloop.io> Date: Fri, 2 Feb 2024 15:49:08 +0100 Subject: [PATCH 5/5] Docs(web): Add demo with Tooltip on Icon element - New demo with tooltip on Icon element --- .../src/scss/components/Tooltip/index.html | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/web/src/scss/components/Tooltip/index.html b/packages/web/src/scss/components/Tooltip/index.html index 3b8f4c7802..a6f4064988 100644 --- a/packages/web/src/scss/components/Tooltip/index.html +++ b/packages/web/src/scss/components/Tooltip/index.html @@ -444,6 +444,53 @@ <h2 class="docs-Heading">Dismissible Tooltip via JS API and Floating UI</h2> </section> + <section class="docs-Section spirit-feature-tooltip-enable-data-placement"> + + <h2 class="docs-Heading">Tooltip on Icon Component</h2> + + <div class="docs-Stack docs-Stack--start"> + + <span> + Click on the icon on the right to view the tooltip + <div class="TooltipWrapper d-inline-block" data-spirit-element="tooltip-wrapper"> + <svg + width="16" + height="16" + data-spirit-toggle="tooltip" + data-spirit-target="#tooltip-example-with-icon"> + <use xlink:href="/icons/svg/sprite.svg#info"/> + </svg> + <div + id="tooltip-example-with-icon" + class="Tooltip Tooltip--dismissible is-hidden" + data-spirit-placement="right" + data-spirit-flip="true" + data-spirit-flip-cross-axis="true" + data-spirit-flip-fallback-placements="top-start, bottom-start, left" + data-spirit-placement-controlled + > + Close me + <button + id="tooltip-example-with-icon-button" + type="button" + class="Tooltip__close" + aria-controls="tooltip-example-with-icon" + aria-expanded="true" + > + <svg width="24" height="24" aria-hidden="true"> + <use xlink:href="/icons/svg/sprite.svg#close" /> + </svg> + <span class="accessibility-hidden">Close</span> + </button> + <span class="Tooltip__arrow" data-spirit-element="arrow"></span> + </div> + </div> + </span> + + </div> + + </section> + <section class="docs-Section spirit-feature-tooltip-enable-data-placement"> <script type="module" src="floating-ui-example.mjs"></script>