From dfdafdbd093aafc9b762f373df2d95d9a1ced529 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Mon, 4 Aug 2025 20:44:00 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=96=8C=EF=B8=8F=20feat:=20add=20animation?= =?UTF-8?q?=20styles=20for=20popovers=20and=20tooltips=20(#8831)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Update client version to 0.2.2 and add animation styles for popovers and tooltips * refactor: Remove focus outline styles from Dropdown component * feat: Update client version to 0.2.3 and add Select component export --------- Co-authored-by: Danny Avila --- package-lock.json | 2 +- packages/client/package.json | 2 +- .../client/src/components/AnimatePopover.css | 27 +++++++ .../client/src/components/ControlCombobox.tsx | 1 + packages/client/src/components/Dropdown.css | 78 +++++++++++++++++++ packages/client/src/components/Dropdown.tsx | 1 + .../client/src/components/DropdownPopup.tsx | 1 + .../client/src/components/MultiSelect.tsx | 1 + packages/client/src/components/Select.tsx | 1 - packages/client/src/components/Tooltip.css | 20 +++++ packages/client/src/components/Tooltip.tsx | 1 + packages/client/src/components/index.ts | 1 + 12 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 packages/client/src/components/AnimatePopover.css create mode 100644 packages/client/src/components/Dropdown.css create mode 100644 packages/client/src/components/Tooltip.css diff --git a/package-lock.json b/package-lock.json index dff97b559d..426a4a7db4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51507,7 +51507,7 @@ }, "packages/client": { "name": "@librechat/client", - "version": "0.2.1", + "version": "0.2.3", "devDependencies": { "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-commonjs": "^25.0.2", diff --git a/packages/client/package.json b/packages/client/package.json index ee22cadfa2..0e6a19aeb8 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@librechat/client", - "version": "0.2.1", + "version": "0.2.3", "description": "React components for LibreChat", "main": "dist/index.js", "module": "dist/index.es.js", diff --git a/packages/client/src/components/AnimatePopover.css b/packages/client/src/components/AnimatePopover.css new file mode 100644 index 0000000000..5a83bfa64f --- /dev/null +++ b/packages/client/src/components/AnimatePopover.css @@ -0,0 +1,27 @@ +.animate-popover { + transform-origin: top; + opacity: 0; + transition: + opacity 150ms cubic-bezier(0.4, 0, 0.2, 1), + transform 150ms cubic-bezier(0.4, 0, 0.2, 1); + transform: scale(0.95) translateY(-0.5rem); +} + +.animate-popover[data-enter] { + opacity: 1; + transform: scale(1) translateY(0); +} + +.animate-popover-left { + transform-origin: left; + opacity: 0; + transition: + opacity 150ms cubic-bezier(0.4, 0, 0.2, 1), + transform 150ms cubic-bezier(0.4, 0, 0.2, 1); + transform: scale(0.95) translateX(-0.5rem); +} + +.animate-popover-left[data-enter] { + opacity: 1; + transform: scale(1) translateX(0); +} diff --git a/packages/client/src/components/ControlCombobox.tsx b/packages/client/src/components/ControlCombobox.tsx index c3d00b0d2d..e512b11a54 100644 --- a/packages/client/src/components/ControlCombobox.tsx +++ b/packages/client/src/components/ControlCombobox.tsx @@ -4,6 +4,7 @@ import { Search, ChevronDown } from 'lucide-react'; import { useMemo, useState, useRef, memo, useEffect } from 'react'; import { SelectRenderer } from '@ariakit/react-core/select/select-renderer'; import type { OptionWithIcon } from '~/common'; +import './AnimatePopover.css'; import { cn } from '~/utils'; interface ControlComboboxProps { diff --git a/packages/client/src/components/Dropdown.css b/packages/client/src/components/Dropdown.css new file mode 100644 index 0000000000..e529af953f --- /dev/null +++ b/packages/client/src/components/Dropdown.css @@ -0,0 +1,78 @@ +.popover-ui { + display: flex; + max-height: min(var(--popover-available-height, 1700px), 1700px); + flex-direction: column; + overflow: auto; + overscroll-behavior: contain; + border-radius: 1rem; + border-width: 1px; + border-style: solid; + border-color: var(--border-light); + background-color: var(--surface-primary); + padding: 0.5rem; + color: var(--text-primary); + box-shadow: + 0 10px 15px -3px rgb(0 0 0 / 0.1), + 0 4px 6px -4px rgb(0 0 0 / 0.1); + transform-origin: top; + opacity: 0; + transition-property: opacity, scale, translate; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + scale: 0.95; + translate: 0 -0.5rem; + margin-top: 4px; + margin-right: -2px; +} + +.popover-animate { + opacity: 0; + transform: scale(0.95) translateY(-0.5rem); + transition: + opacity 150ms cubic-bezier(0.4, 0, 0.2, 1), + transform 150ms cubic-bezier(0.4, 0, 0.2, 1); +} +.popover-animate[data-enter] { + opacity: 1; + transform: scale(1) translateY(0); +} + +.popover-ui:focus-visible, +.popover-ui[data-focus-visible] { + outline: var(--bg-surface-hover); + outline-offset: -1px; +} + +.popover-ui:where(.dark, .dark *) { + background-color: var(--surface-secondary); + color: var(--text-secondary); + box-shadow: + 0 10px 15px -3px rgb(0 0 0 / 0.25), + 0 4px 6px -4px rgb(0 0 0 / 0.1); +} + +.select-item { + display: flex; + cursor: pointer; + scroll-margin: 0.5rem; + align-items: center; + gap: 0.5rem; + border-radius: 0.5rem; + padding: 0.5rem; + outline: none !important; +} + +.select-item[aria-disabled='true'] { + opacity: 0.5; +} + +.select-item[data-active-item] { + background-color: var(--surface-hover); + color: var(--text-primary); +} + +.popover-ui[data-enter] { + opacity: 1; + scale: 1; + translate: 0; +} diff --git a/packages/client/src/components/Dropdown.tsx b/packages/client/src/components/Dropdown.tsx index 2cb94f2b02..b191878c81 100644 --- a/packages/client/src/components/Dropdown.tsx +++ b/packages/client/src/components/Dropdown.tsx @@ -2,6 +2,7 @@ import React from 'react'; import * as Select from '@ariakit/react/select'; import type { Option } from '~/common'; import { cn } from '~/utils/'; +import './Dropdown.css'; interface DropdownProps { value?: string; diff --git a/packages/client/src/components/DropdownPopup.tsx b/packages/client/src/components/DropdownPopup.tsx index 0953811f49..9d4c7f1537 100644 --- a/packages/client/src/components/DropdownPopup.tsx +++ b/packages/client/src/components/DropdownPopup.tsx @@ -2,6 +2,7 @@ import React from 'react'; import * as Ariakit from '@ariakit/react'; import type * as t from '~/common'; import { cn } from '~/utils'; +import './Dropdown.css'; interface DropdownProps { keyPrefix?: string; diff --git a/packages/client/src/components/MultiSelect.tsx b/packages/client/src/components/MultiSelect.tsx index d7798e810d..a793e1c550 100644 --- a/packages/client/src/components/MultiSelect.tsx +++ b/packages/client/src/components/MultiSelect.tsx @@ -8,6 +8,7 @@ import { SelectPopover, SelectProvider, } from '@ariakit/react'; +import './AnimatePopover.css'; import { cn } from '~/utils'; interface MultiSelectProps { diff --git a/packages/client/src/components/Select.tsx b/packages/client/src/components/Select.tsx index 3301e3577c..39f32f4f3a 100644 --- a/packages/client/src/components/Select.tsx +++ b/packages/client/src/components/Select.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import * as SelectPrimitive from '@radix-ui/react-select'; import { CaretSortIcon, CheckIcon, ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons'; - import { cn } from '~/utils'; // @ts-ignore - Radix UI type conflicts with React types diff --git a/packages/client/src/components/Tooltip.css b/packages/client/src/components/Tooltip.css new file mode 100644 index 0000000000..92e52037c4 --- /dev/null +++ b/packages/client/src/components/Tooltip.css @@ -0,0 +1,20 @@ +.tooltip { + z-index: 50; + cursor: pointer; + border-radius: 0.275rem; + background-color: var(--surface-primary); + padding-top: 0.25rem; + padding-bottom: 0.25rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + font-size: 1rem; + line-height: 1.5rem; + color: black; + box-shadow: 0 2px 4px 0 rgb(0 0 0 / 0.25); +} + +.tooltip:where(.dark, .dark *) { + background-color: var(--surface-primary); + color: white; + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.35); +} diff --git a/packages/client/src/components/Tooltip.tsx b/packages/client/src/components/Tooltip.tsx index 2bf89e24d0..b83452d654 100644 --- a/packages/client/src/components/Tooltip.tsx +++ b/packages/client/src/components/Tooltip.tsx @@ -2,6 +2,7 @@ import * as Ariakit from '@ariakit/react'; import { AnimatePresence, motion } from 'framer-motion'; import { forwardRef, useMemo } from 'react'; import { cn } from '~/utils'; +import './Tooltip.css'; interface TooltipAnchorProps extends Ariakit.TooltipAnchorProps { description: string; diff --git a/packages/client/src/components/index.ts b/packages/client/src/components/index.ts index 0269a04550..f315a2ca16 100644 --- a/packages/client/src/components/index.ts +++ b/packages/client/src/components/index.ts @@ -30,6 +30,7 @@ export * from './Progress'; export * from './InputOTP'; export * from './MultiSearch'; export * from './Resizable'; +export * from './Select'; export { default as Radio } from './Radio'; export { default as Badge } from './Badge'; export { default as Combobox } from './Combobox';