From 0ec6166c4eb023cd1c03c11cf95a8568e65c6aec Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Wed, 30 Apr 2025 15:33:05 +0100 Subject: [PATCH 01/12] Add max-width to the tooltip --- web/libs/ui/src/lib/Tooltip/Tooltip.module.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss index d44297940275..f95f3f54fffd 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss @@ -18,6 +18,7 @@ pointer-events: none; background-color: var(--color-neutral-inverted-background); border-radius: 3px; + max-width: 250px; &::before { left: 50%; From 2b17a49a6ee458bb37de95efa4198112a3fbc106 Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Fri, 2 May 2025 14:31:48 +0100 Subject: [PATCH 02/12] Allow setting different width via `className` --- web/libs/ui/src/lib/Tooltip/Tooltip.tsx | 29 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.tsx b/web/libs/ui/src/lib/Tooltip/Tooltip.tsx index b1529f82c34d..91deb4b51580 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.tsx +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.tsx @@ -27,10 +27,24 @@ export type TooltipProps = PropsWithChildren<{ children: React.ReactNode; interactive?: boolean; theme?: "light" | "dark"; + className?: string; }>; const TooltipInner = forwardRef( - ({ title, children, alignment, defaultVisible, disabled, style, interactive, theme = "dark" }: TooltipProps, ref) => { + ( + { + title, + children, + alignment, + defaultVisible, + disabled, + style, + interactive, + theme = "dark", + className, + }: TooltipProps, + ref, + ) => { const triggerElement = useRef(); const tooltipElement = useRef(); const hideTimeoutRef = useRef(); @@ -101,10 +115,15 @@ const TooltipInner = forwardRef( injected ? (
setRef(tooltipElement, el)} - className={clsx(styles.tooltip, visibilityClasses, { - [styles[`tooltip_align_${align}`]]: true, - [styles.tooltip_theme_light]: theme === "light", - })} + className={clsx( + styles.tooltip, + visibilityClasses, + { + [styles[`tooltip_align_${align}`]]: true, + [styles.tooltip_theme_light]: theme === "light", + }, + className, + )} style={{ ...offset, ...style, From 0884c4f8a920d30e5ff9739b647e0c728ccf7c67 Mon Sep 17 00:00:00 2001 From: MihajloHoma Date: Mon, 5 May 2025 06:33:57 +0000 Subject: [PATCH 03/12] Sync Follow Merge dependencies Workflow run: https://github.com/HumanSignal/label-studio/actions/runs/14830445565 --- poetry.lock | 32 +++----------------------------- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/poetry.lock b/poetry.lock index a8cc38d3ac72..b6441cd53a92 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2126,7 +2126,7 @@ optional = false python-versions = ">=3.9,<4" groups = ["main"] files = [ - {file = "1a8ad39a63f2771db112fb488f131daf5052bad1.zip", hash = "sha256:0dfcf091a211f23d184aee99160dd9be776b50bdc23a759dab735d815e76e8f2"}, + {file = "1ef88e2f8afe50a738fc1b03385cb1f3d6b2dd9f.zip", hash = "sha256:c81daeb4fae81cdc5bc25bcf1e86a19cb887abb0c6e0404c2f49c1e7a7dd1cbf"}, ] [package.dependencies] @@ -2139,7 +2139,6 @@ jsonschema = ">=4.23.0" lxml = ">=4.2.5" nltk = ">=3.9.1,<4.0.0" numpy = ">=1.26.4,<3.0.0" -opencv-python = ">=4.9.0,<5.0.0" pandas = ">=0.24.0" Pillow = ">=10.0.1" pydantic = ">=1.9.2" @@ -2153,7 +2152,7 @@ xmljson = "0.2.1" [package.source] type = "url" -url = "https://github.com/HumanSignal/label-studio-sdk/archive/1a8ad39a63f2771db112fb488f131daf5052bad1.zip" +url = "https://github.com/HumanSignal/label-studio-sdk/archive/1ef88e2f8afe50a738fc1b03385cb1f3d6b2dd9f.zip" [[package]] name = "launchdarkly-server-sdk" @@ -2700,31 +2699,6 @@ typing-extensions = ">=4.7,<5" [package.extras] datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] -[[package]] -name = "opencv-python" -version = "4.11.0.86" -description = "Wrapper package for OpenCV python bindings." -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4"}, - {file = "opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:432f67c223f1dc2824f5e73cdfcd9db0efc8710647d4e813012195dc9122a52a"}, - {file = "opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:9d05ef13d23fe97f575153558653e2d6e87103995d54e6a35db3f282fe1f9c66"}, - {file = "opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b92ae2c8852208817e6776ba1ea0d6b1e0a1b5431e971a2a0ddd2a8cc398202"}, - {file = "opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b02611523803495003bd87362db3e1d2a0454a6a63025dc6658a9830570aa0d"}, - {file = "opencv_python-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:810549cb2a4aedaa84ad9a1c92fbfdfc14090e2749cedf2c1589ad8359aa169b"}, - {file = "opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec"}, -] - -[package.dependencies] -numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, - {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""}, - {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\""}, -] - [[package]] name = "ordered-set" version = "4.0.2" @@ -4976,4 +4950,4 @@ uwsgi = ["pyuwsgi", "uwsgitop"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4" -content-hash = "c90e8148ff5bc241166077037276990416f203d2ba573403bd98d18f4c2e0292" +content-hash = "88140370916383f3045ee7dddba219ddc7fb5a3133e932edcccb2f305d921c67" diff --git a/pyproject.toml b/pyproject.toml index c29be7a0949c..14cdf8dc6395 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -210,7 +210,7 @@ djangorestframework-simplejwt = {extras = ["crypto"], version = "^5.4.0"} tldextract = ">=5.1.3" # Humansignal repo dependencies -label-studio-sdk = {url = "https://github.com/HumanSignal/label-studio-sdk/archive/1a8ad39a63f2771db112fb488f131daf5052bad1.zip"} +label-studio-sdk = {url = "https://github.com/HumanSignal/label-studio-sdk/archive/1ef88e2f8afe50a738fc1b03385cb1f3d6b2dd9f.zip"} [tool.poetry.group.test.dependencies] pytest = "7.2.2" From 66528efbffc0be2c80110995f861fb156a248d98 Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Mon, 5 May 2025 10:20:40 +0100 Subject: [PATCH 04/12] Update text wrapping --- web/libs/ui/src/lib/Tooltip/Tooltip.module.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss index f95f3f54fffd..f2b0a4d986bc 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss @@ -18,6 +18,8 @@ pointer-events: none; background-color: var(--color-neutral-inverted-background); border-radius: 3px; + white-space: normal; + overflow-wrap: break-word; max-width: 250px; &::before { From 1d9230fe049238dd7fa7dcdc6c98b69d6cdcbb55 Mon Sep 17 00:00:00 2001 From: MihajloHoma Date: Tue, 6 May 2025 06:47:50 +0000 Subject: [PATCH 05/12] Sync Follow Merge dependencies Workflow run: https://github.com/HumanSignal/label-studio/actions/runs/14853321127 --- poetry.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 06dafabbd2a1..af21856228f1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -4951,4 +4951,4 @@ uwsgi = ["pyuwsgi", "uwsgitop"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<4" -content-hash = "88140370916383f3045ee7dddba219ddc7fb5a3133e932edcccb2f305d921c67" +content-hash = "bd6b7cec643037a5a8f5c5f0ed6e8b9f5ced3f4a6db41bc63d4d5488fcf58b2b" From c4b28f75b937ea5c1085ff2de763bc2bc9f45fe5 Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Tue, 6 May 2025 16:50:55 +0100 Subject: [PATCH 06/12] Fix long text display --- .../ui/src/lib/Tooltip/Tooltip.module.scss | 2 +- .../ui/src/lib/Tooltip/tooltip.stories.tsx | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss index f2b0a4d986bc..3c765de11300 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss @@ -19,7 +19,7 @@ background-color: var(--color-neutral-inverted-background); border-radius: 3px; white-space: normal; - overflow-wrap: break-word; + overflow-wrap: anywhere; max-width: 250px; &::before { diff --git a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx new file mode 100644 index 000000000000..69551e984202 --- /dev/null +++ b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx @@ -0,0 +1,50 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Tooltip } from "./Tooltip"; + +const meta: Meta = { + component: Tooltip, + title: "UI/Tooltip", + tags: ["autodocs"], + argTypes: { + disabled: { control: "boolean" }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + render: ({ children, ...props }) => { + return ( +
+ +
hover over me
+
+
+ ); + }, +}; + +export const WithLongText: Story = { + render: ({ children, ...props }) => { + return ( +
+ +
hover over me
+
+
+ ); + }, +}; + +export const WithLongTextString: Story = { + render: ({ children, ...props }) => { + return ( +
+ +
hover over me
+
+
+ ); + }, +}; From 5200994cc5be8611f3da55086c317a16f429c068 Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Tue, 6 May 2025 16:56:04 +0100 Subject: [PATCH 07/12] Add interactive example --- .../ui/src/lib/Tooltip/Tooltip.module.scss | 2 +- .../ui/src/lib/Tooltip/tooltip.stories.tsx | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss index 3c765de11300..85ea10563906 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss @@ -19,7 +19,7 @@ background-color: var(--color-neutral-inverted-background); border-radius: 3px; white-space: normal; - overflow-wrap: anywhere; + overflow-wrap: anywher ; max-width: 250px; &::before { diff --git a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx index 69551e984202..44afea871c8a 100644 --- a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx +++ b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx @@ -48,3 +48,23 @@ export const WithLongTextString: Story = { ); }, }; + +export const Interactive: Story = { + render: ({ children, ...props }) => { + return ( +
+ + +
+ } + interactive + > +
hover over me
+ +
+ ); + }, +}; From f32670fae9e35adeafcfbbe99f78c31b32625a33 Mon Sep 17 00:00:00 2001 From: AndrejOros Date: Wed, 7 May 2025 08:30:33 +0000 Subject: [PATCH 08/12] Sync Follow Merge dependencies Workflow run: https://github.com/HumanSignal/label-studio/actions/runs/14878760207 From e9d364feff9f0a904b3f37702c4085eb4244c504 Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Wed, 14 May 2025 16:03:53 +0100 Subject: [PATCH 09/12] Add button states --- web/libs/ui/src/lib/button/button.module.scss | 96 ++++++++++-------- web/libs/ui/src/lib/button/button.stories.tsx | 74 +++++++++++++- web/libs/ui/src/lib/button/button.tsx | 98 +++++++++++++++---- 3 files changed, 207 insertions(+), 61 deletions(-) diff --git a/web/libs/ui/src/lib/button/button.module.scss b/web/libs/ui/src/lib/button/button.module.scss index 7cdc13042875..66b97065abdc 100644 --- a/web/libs/ui/src/lib/button/button.module.scss +++ b/web/libs/ui/src/lib/button/button.module.scss @@ -15,38 +15,20 @@ --emboss-shadow: inset 0 1px 0 rgb(var(--white-raw) / 10%), inset 0 -1px 0 rgb(var(--black-raw) / 10%); --emboss-shadow-active: inset 0 -1px 0 rgb(var(--white-raw) / 5%), inset 0 1px 0 rgb(var(--black-raw) / 10%); - @apply text-label-medium font-medium; - - box-shadow: var(--emboss-shadow); - background-color: var(--background-color); - background-image: var(--background-image); - border-color: var(--border-color); - color: var(--text-color); - text-align: center; - - - & > span { - @apply inline-flex flex-1 whitespace-pre items-center px-tight; - } - - svg { - @apply h-6 inline-block aspect-square; - } - & > span:not(:has(text)):has(svg:only-child) { @apply h-full w-full p-0 aspect-square; } - &:hover { - background-color: var(--background-color-hover); - border-color: var(--border-color-hover); + & > em { + @apply inline-flex; + + & > svg { + @apply h-full aspect-square; + } } &:active { --emboss-shadow: var(--emboss-shadow-active); - - background-color: var(--background-color-active); - border-color: var(--border-color-hover); } &:focus { @@ -153,11 +135,11 @@ .variant-neutral-interted { --background-color: var(--color-neutral-inverted-surface); - --border-color: var(--color-neutral-inverted-border-bold); + --border-color: var(--color-neutral-inverted-border); --text-color: var(--color-neutral-inverted-content); --background-color-hover: var(--color-neutral-inverted-surface-hover); --background-color-active: var(--color-neutral-inverted-surface-active); - --focus-outline: var(--color-neutral-inverted-focus-outline); + --focus-outline: var(--color-primary-focus-outline); --background-color-hover-outline: var(--color-neutral-inverted-emphasis-subtle); --background-color-active-outline: var(--color-neutral-inverted-emphasis); --border-outline: var(--color-neutral-inverted-border); @@ -171,7 +153,7 @@ .look-outlined { &:not(:disabled), &.waiting { - --background-color: transparent; + --background-color: var(--color-neutral-background); --border-color: var(--border-outline); --text-color: var(--text-outline); --background-color-hover: var(--background-color-hover-outline); @@ -214,47 +196,55 @@ border-color: var(--border-color-hover); } } + + &:disabled:not(.waiting), + &:disabled:not(.waiting):hover, + &:disabled:not(.waiting):focus, + &:disabled:not(.waiting):active { + --background-color-hover: transparent; + --background-color-active: transparent; + --border-color-hover: transparent; + --background-color: transparent; + --border-color: transparent; + } } /// SIZES .size-medium { - @apply p-tight text-label-medium h-[40px]; + @apply p-tight text-label-medium h-1000; & > span { @apply px-tight gap-tight; } - & > svg { - @apply h-6; + & > em { + @apply gap-tight h-600 min-w-600; } } .size-small { - @apply p-tighter text-label-small h-[32px]; + @apply p-tighter text-label-small h-800; + & > span { @apply px-tighter gap-tighter; } - & > svg { - @apply h-4; + & > em { + @apply gap-tighter h-400 min-w-400; } } .size-smaller { - @apply p-tightest text-label-smaller h-[24px]; + @apply p-tightest text-label-smaller h-600; & > span { @apply px-tightest gap-tightest; } - & > svg, & > span > svg { - @apply h-4; - } - - & > svg { - @apply w-4; + & > em { + @apply gap-tighter h-400 min-w-400; } } @@ -320,3 +310,29 @@ @apply justify-end; } } + +.button-group { + @apply flex gap-tight; + + &.button-group-collapsed { + @apply gap-0; + + button:not(:first-child) { + border-left: none; + } + + button:first-child:not(:only-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + button:last-child:not(:only-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + + button:not(:first-child, :last-child) { + border-radius: 0; + } + } +} diff --git a/web/libs/ui/src/lib/button/button.stories.tsx b/web/libs/ui/src/lib/button/button.stories.tsx index 673f5fbd0b97..bb7b9c8847a6 100644 --- a/web/libs/ui/src/lib/button/button.stories.tsx +++ b/web/libs/ui/src/lib/button/button.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Button, buttonVariant } from "./button"; -import { IconAnnotationGroundTruth } from "@humansignal/icons"; +import { IconAnnotationGroundTruth, IconCrossAlt } from "@humansignal/icons"; const meta: Meta = { component: Button, @@ -62,6 +62,24 @@ export const WithAlignment: Story = { }, }; +export const WithSize: Story = { + render: ({ children, ...props }) => { + return ( +
+ + + +
+ ); + }, +}; + export const WithIcon: Story = { render: ({ children, ...props }) => { return ( @@ -119,12 +137,40 @@ export const WithComplexChildren: Story = { }, }; +export const WithExtra: Story = { + args: { + children: "Button with an", + align: "default", + }, + render: ({ children, ...props }) => { + return ( + + ); + }, +}; + export const IconButton: Story = { render: ({ children: _, ...props }) => { return ( - +
+ + + +
); }, }; @@ -142,3 +188,23 @@ export const StyledLink: Story = { ); }, }; + +export const WithSecondaryAction = { + args: { + children: "Link with button style", + }, + render({ children, ...props }) { + return ( + // biome-ignore lint: We don't need a real link here + + ); + }, +}; diff --git a/web/libs/ui/src/lib/button/button.tsx b/web/libs/ui/src/lib/button/button.tsx index f7092260cd40..2a064dfd5940 100644 --- a/web/libs/ui/src/lib/button/button.tsx +++ b/web/libs/ui/src/lib/button/button.tsx @@ -1,6 +1,8 @@ import { cn } from "../../utils/utils"; -import { forwardRef, type ButtonHTMLAttributes, type PropsWithChildren, type ReactNode } from "react"; +import { forwardRef, type MouseEvent, type ButtonHTMLAttributes, type PropsWithChildren, type ReactNode } from "react"; import styles from "./button.module.scss"; +import { setRef } from "@humansignal/core/lib/utils/unwrapRef"; +import { Tooltip } from "../Tooltip/Tooltip"; const variants = { primary: styles["variant-primary"], @@ -30,6 +32,10 @@ const alignment = { right: styles["align-right"], }; +export type ButtonVariant = ButtonProps["variant"]; +export type ButtonLook = ButtonProps["look"]; +export type ButtonSize = ButtonProps["size"]; + /** * Generates a className string with button styling that can be applied to any element * @@ -56,12 +62,16 @@ export function buttonVariant( size?: ButtonProps["size"]; align?: ButtonProps["align"]; waiting?: boolean; - }, + } = {}, className?: string, ) { const buttonStyles = [styles.base, variants[variant], looks[look], sizes[size], alignment[align]]; return cn( "inline-flex items-center rounded-smaller border text-shadow-button box-border border transition-all", + "text-label-medium font-medium text-[color:--text-color] bg-[color:--background-color] bg-[image:--background-image] border-[color:--border-color] shadow-[shadow:--emboss-shadow] text-center", + "hover:text-[color:--text-color] hover:bg-[color:--background-color-hover] hover:border-[color:--border-color-hover]", + "active:bg-[color:--background-color-active] active:border-[color:--border-color]", + "[&_svg]:h-full [&_svg]:inline-block [&_svg]:aspect-square", ...buttonStyles, { [styles.waiting]: waiting }, className, @@ -69,13 +79,47 @@ export function buttonVariant( } export type ButtonProps = { + /** + * Controls the color variant of the button + * See [Storybook](https://labelstud.io/storybook?path=/docs/ui-button--docs) + */ variant?: keyof typeof variants; + /** + * Controls the look of the button + * See [Storybook](https://labelstud.io/storybook?path=/docs/ui-button--docs) + */ look?: keyof typeof looks; size?: keyof typeof sizes; align?: keyof typeof alignment; + /** + * Waiting state with stripes animation + */ waiting?: boolean; + /** + * Allow button to be clickable when waiting + */ + waitingClickable?: boolean; + /** + * @deprecated Use `leading` instead + */ + icon?: ReactNode; + /** + * Inserts a leading element preceding the content of the button + */ leading?: ReactNode; + /** + * Inserts a trailing element following the content of the button + */ trailing?: ReactNode; + /** + * Adds a tooltip to the button + */ + tooltip?: string; + /** + * When in waiting state with `waitingClickable` enabled, this function will be used + * as `onClick` if provided. Otherwise default `onClick` will be used. + */ + secondaryOnClick?: (e: MouseEvent) => void; } & ButtonHTMLAttributes; /** @@ -84,6 +128,11 @@ export type ButtonProps = { * The Button component provides a consistent UI element for user interactions * with support for different visual variants, looks, and sizes. It can include * leading and trailing elements for additional visual context. + * + * Features: + * - Different colors and looks of the button + * - Waiting state with secondary action + * - Icons support */ const Button = forwardRef( ( @@ -95,30 +144,45 @@ const Button = forwardRef( size = "medium", waiting = false, align = "default", - leading, + waitingClickable = false, + icon, + leading = icon, trailing, + tooltip, + onClick, + secondaryOnClick, ...buttonProps }: PropsWithChildren, ref, - ) => { - return ( + ): JSX.Element => { + const buttonClassName = cn(buttonVariant({ variant, look, size, waiting, align }, className)); + const iconClassName = "inline-flex gap-tight not-italic items-center"; + const contentClassName = "inline-flex flex-1 whitespace-pre items-center px-tight"; + const clickHandler = waiting && waitingClickable ? (secondaryOnClick ?? onClick) : onClick; + + const buttonBody = ( ); + + if (tooltip) { + return {buttonBody}; + } + + return buttonBody as JSX.Element; }, ); From c8b2a2f79c25b098f849de8db65d9e716246062b Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Wed, 14 May 2025 16:09:56 +0100 Subject: [PATCH 10/12] Add button type to tooltip example --- web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx index 44afea871c8a..71cc928d3362 100644 --- a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx +++ b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx @@ -57,7 +57,9 @@ export const Interactive: Story = { {...props} title={
- +
} interactive From b2b9a7f607d251ff0464ec9e6987879c90944b9e Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Wed, 14 May 2025 16:12:27 +0100 Subject: [PATCH 11/12] Fix text wrapping --- web/libs/ui/src/lib/Tooltip/Tooltip.module.scss | 3 ++- web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss index 85ea10563906..577d17daccab 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss @@ -19,7 +19,8 @@ background-color: var(--color-neutral-inverted-background); border-radius: 3px; white-space: normal; - overflow-wrap: anywher ; + overflow-wrap: anywhere; + overflow: hidden; max-width: 250px; &::before { diff --git a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx index 71cc928d3362..76728bda0981 100644 --- a/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx +++ b/web/libs/ui/src/lib/Tooltip/tooltip.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { Tooltip } from "./Tooltip"; +import { Button } from "../button/button"; const meta: Meta = { component: Tooltip, @@ -18,7 +19,7 @@ export const Primary: Story = { return (
-
hover over me
+
); @@ -30,7 +31,7 @@ export const WithLongText: Story = { return (
-
hover over me
+
); @@ -42,7 +43,7 @@ export const WithLongTextString: Story = { return (
-
hover over me
+
); @@ -64,7 +65,7 @@ export const Interactive: Story = { } interactive > -
hover over me
+ ); From 56a70552b5dddaa078ad151b0775dbb48a3cfc60 Mon Sep 17 00:00:00 2001 From: Nick Skriabin Date: Wed, 14 May 2025 16:12:54 +0100 Subject: [PATCH 12/12] Fix overflow --- web/libs/ui/src/lib/Tooltip/Tooltip.module.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss index 577d17daccab..3c765de11300 100644 --- a/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss +++ b/web/libs/ui/src/lib/Tooltip/Tooltip.module.scss @@ -20,7 +20,6 @@ border-radius: 3px; white-space: normal; overflow-wrap: anywhere; - overflow: hidden; max-width: 250px; &::before {