diff --git a/.pnp.cjs b/.pnp.cjs index aebfb90bd..c5c58c05d 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2013,6 +2013,7 @@ const RAW_RUNTIME_STATE = ["@atls-ui-parts/tooltip", "workspace:ui-parts/tooltip"],\ ["@atls-ui-parts/condition", "virtual:da655f76fb0a7abb1a892608b634316179378c6672ef2e4237cfc638bc59c4632d4d90add99f0f36fc3476fd7ba3bfb9b8da134f89edd82cecf6748f1bd98e54#workspace:ui-parts/condition"],\ ["@atls-ui-parts/layout", "virtual:dbe1a421eee484ea0bdb9d0589d44d9184c9819d8f5bfcb1a73e3d85271cc45ecf4365a26e00f2a3256c13de48b40272578801688978809175001fb2693bc747#workspace:ui-parts/layout"],\ + ["@atls-ui-parts/theme", "virtual:dbe1a421eee484ea0bdb9d0589d44d9184c9819d8f5bfcb1a73e3d85271cc45ecf4365a26e00f2a3256c13de48b40272578801688978809175001fb2693bc747#workspace:ui-parts/theme"],\ ["@atls-utils/use-float", "virtual:e8b379d238bee0c446fdeaddb9725553fcee91eeb8db9f1f4b47e4e36a5c6c26c07ae1861b7d0a5dd574863bc008f048d25fc793392ceeaade0c9801b921d418#workspace:utils/use-float"],\ ["@floating-ui/react", "virtual:bdec61daa5ce18b211e41086a87aa58babcd016eed745eb318a2389812d34b0215bd01c4e05f4de11cfc30bd0259efe6cace4826920dba58cacb6c2dd7978d3e#npm:0.27.8"],\ ["@storybook/react", "virtual:90c3fa37a29dbddd012ae896ef9d136c46ca1d320faf1baf430439ab5aac7e1e7c8ef5281a72424df8d016a8c33c9d5ffe66ee23d2face19f27de3042508900f#npm:8.6.12"],\ diff --git a/ui-parts/tooltip/package.json b/ui-parts/tooltip/package.json index 7192977e1..9b2c60d4a 100644 --- a/ui-parts/tooltip/package.json +++ b/ui-parts/tooltip/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@atls-ui-parts/condition": "workspace:*", + "@atls-ui-parts/theme": "workspace:*", "@atls-utils/use-float": "workspace:*", "@floating-ui/react": "0.27.8", "framer-motion": "12.23.22" diff --git a/ui-parts/tooltip/src/component.tsx b/ui-parts/tooltip/src/component.tsx index 9574b2a04..a1e0d615d 100644 --- a/ui-parts/tooltip/src/component.tsx +++ b/ui-parts/tooltip/src/component.tsx @@ -1,35 +1,51 @@ -import type { ReactNode } from 'react' +import type { ReactNode } from 'react' -import type { TooltipProps } from './interfaces.js' +import type { TooltipProps } from './interfaces.js' -import { FloatingPortal } from '@floating-ui/react' -import { AnimatePresence } from 'framer-motion' -import { motion } from 'framer-motion' -import { cloneElement } from 'react' +import { FloatingPortal } from '@floating-ui/react' +import { AnimatePresence } from 'framer-motion' +import { motion } from 'framer-motion' +import { cloneElement } from 'react' -import { useFloat } from '@atls-utils/use-float' +import { useFloat } from '@atls-utils/use-float' -import { Arrow } from './arrow/index.js' -import { Container } from './container/index.js' -import { animateProps } from './constants.js' +import { Arrow } from './arrow/index.js' +import { Container } from './container/index.js' +import { animateProps } from './constants.js' +import { tooltipAppearances } from './styles/index.js' +import { tooltipShapes } from './styles/index.js' export const Tooltip = ({ + appearance, children, text, open, - container = , + container, animated = true, arrow = true, + shape, ...props }: TooltipProps): ReactNode => { const { arrowRef, refs, isOpen, context, floatingStyles, getFloatingProps, getReferenceProps } = useFloat({ open, role: 'tooltip', ...props }) + const containerElement = container ?? + const defaultAppearance = container === undefined ? tooltipAppearances.default : undefined + const defaultShape = container === undefined ? tooltipShapes.default : undefined + const containerAppearance = appearance ?? defaultAppearance + const containerShape = shape ?? defaultShape const TriggerElement = cloneElement(children, { ref: refs.setReference, ...getReferenceProps() }) + const containerClassName = [ + containerElement.props.className, + containerAppearance?.container, + containerShape?.container, + ] + .filter(Boolean) + .join(' ') const ContainerElement = cloneElement( - container, - { open: isOpen }, + containerElement, + { className: containerClassName || undefined, open: isOpen }, <> {text} diff --git a/ui-parts/tooltip/src/constants.ts b/ui-parts/tooltip/src/constants.ts index ddd3bdc67..5f92436e2 100644 --- a/ui-parts/tooltip/src/constants.ts +++ b/ui-parts/tooltip/src/constants.ts @@ -1,5 +1,11 @@ import type { MotionProps } from 'framer-motion' +export const DEFAULT_CONTAINER_HEIGHT = 32 + +export const DEFAULT_CONTAINER_MIN_WIDTH = 30 + +export const DEFAULT_CONTAINER_Z_INDEX = 1000 + export const animateProps: MotionProps = { initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, diff --git a/ui-parts/tooltip/src/container/component.tsx b/ui-parts/tooltip/src/container/component.tsx index 3c1bea066..aec564602 100644 --- a/ui-parts/tooltip/src/container/component.tsx +++ b/ui-parts/tooltip/src/container/component.tsx @@ -1,7 +1,8 @@ +import type { HTMLAttributes } from 'react' import type { ReactNode } from 'react' -import { baseContainerStyles } from './styles.css.js' +import { baseContainerStyles } from './container.css.js' -export const Container = (props: {}): ReactNode => ( -
+export const Container = ({ className, ...props }: HTMLAttributes): ReactNode => ( +
) diff --git a/ui-parts/tooltip/src/container/container.css.ts b/ui-parts/tooltip/src/container/container.css.ts new file mode 100644 index 000000000..bb1d76e11 --- /dev/null +++ b/ui-parts/tooltip/src/container/container.css.ts @@ -0,0 +1,9 @@ +import { style } from '@vanilla-extract/css' + +export const baseContainerStyles = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + margin: 0, + wordWrap: 'break-word', +}) diff --git a/ui-parts/tooltip/src/container/styles.css.ts b/ui-parts/tooltip/src/container/styles.css.ts deleted file mode 100644 index 24fceee4a..000000000 --- a/ui-parts/tooltip/src/container/styles.css.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { style } from '@vanilla-extract/css' - -export const baseContainerStyles = style({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - minWidth: 30, - minHeight: 32, - padding: '8px 12px', - margin: 0, - color: 'rgba(255, 255, 255, 1)', - wordWrap: 'break-word', - backgroundColor: 'rgba(0, 0, 0, 0.75)', - borderRadius: '8px', - boxShadow: '0px 2px 24px rgba(0, 0, 0, 0.15)', - zIndex: 1000, -}) diff --git a/ui-parts/tooltip/src/index.ts b/ui-parts/tooltip/src/index.ts index f564fb7d5..5bf8dfad6 100644 --- a/ui-parts/tooltip/src/index.ts +++ b/ui-parts/tooltip/src/index.ts @@ -1,3 +1,4 @@ export * from './arrow/index.js' export * from './component.js' +export * from './styles/index.js' export type * from './interfaces.js' diff --git a/ui-parts/tooltip/src/interfaces.ts b/ui-parts/tooltip/src/interfaces.ts index 0acde2112..d34bd8b24 100644 --- a/ui-parts/tooltip/src/interfaces.ts +++ b/ui-parts/tooltip/src/interfaces.ts @@ -4,10 +4,24 @@ import type { MotionProps } from 'framer-motion' import type { JSX } from 'react' import type { ReactNode } from 'react' +export interface TooltipAppearance { + container: string +} + +export type TooltipAppearanceName = 'default' + +export interface TooltipShape { + container: string +} + +export type TooltipShapeName = 'default' + export interface TooltipProps extends UseFloatProps { + appearance?: TooltipAppearance children: JSX.Element text?: ReactNode container?: JSX.Element animated?: Omit | boolean arrow?: Omit | boolean + shape?: TooltipShape } diff --git a/ui-parts/tooltip/src/styles/appearance.css.ts b/ui-parts/tooltip/src/styles/appearance.css.ts new file mode 100644 index 000000000..b81e1bbbd --- /dev/null +++ b/ui-parts/tooltip/src/styles/appearance.css.ts @@ -0,0 +1,22 @@ +import type { TooltipAppearance } from '../interfaces.js' +import type { TooltipAppearanceName } from '../interfaces.js' + +import { style } from '@vanilla-extract/css' + +import { vars } from '@atls-ui-parts/theme' + +const containerDefaultAppearanceStyles = style({ + color: vars.colors.white, + backgroundColor: vars.colors.blackThreeQuarters, + boxShadow: vars.shadows.gordonsgreen, +}) + +export const appearanceVariant = { + default: { + container: containerDefaultAppearanceStyles, + }, +} + +export const tooltipAppearances: Record = { + default: appearanceVariant.default, +} diff --git a/ui-parts/tooltip/src/styles/index.ts b/ui-parts/tooltip/src/styles/index.ts new file mode 100644 index 000000000..93e0eec5d --- /dev/null +++ b/ui-parts/tooltip/src/styles/index.ts @@ -0,0 +1,2 @@ +export * from './appearance.css.js' +export * from './shape.css.js' diff --git a/ui-parts/tooltip/src/styles/shape.css.ts b/ui-parts/tooltip/src/styles/shape.css.ts new file mode 100644 index 000000000..8a2ca6655 --- /dev/null +++ b/ui-parts/tooltip/src/styles/shape.css.ts @@ -0,0 +1,26 @@ +import type { TooltipShape } from '../interfaces.js' +import type { TooltipShapeName } from '../interfaces.js' + +import { style } from '@vanilla-extract/css' + +import { vars } from '@atls-ui-parts/theme' + +import { DEFAULT_CONTAINER_HEIGHT } from '../constants.js' +import { DEFAULT_CONTAINER_MIN_WIDTH } from '../constants.js' +import { DEFAULT_CONTAINER_Z_INDEX } from '../constants.js' + +const containerDefaultShapeStyles = style({ + minWidth: DEFAULT_CONTAINER_MIN_WIDTH, + minHeight: DEFAULT_CONTAINER_HEIGHT, + padding: `${vars.space.g8} ${vars.space.g12}`, + borderRadius: vars.radii.f8, + zIndex: DEFAULT_CONTAINER_Z_INDEX, +}) + +export const shapeStyles = { + default: { + container: containerDefaultShapeStyles, + }, +} + +export const tooltipShapes: Record = shapeStyles diff --git a/ui-parts/tooltip/stories/interfaces.ts b/ui-parts/tooltip/stories/interfaces.ts index bba6c0b1f..bbd523e8c 100644 --- a/ui-parts/tooltip/stories/interfaces.ts +++ b/ui-parts/tooltip/stories/interfaces.ts @@ -3,4 +3,5 @@ import type { TooltipProps } from '@atls-ui-parts/tooltip' export interface StoryTooltipProps extends Pick { customContainer: boolean + styledContainer: boolean } diff --git a/ui-parts/tooltip/stories/story-tooltip.tsx b/ui-parts/tooltip/stories/story-tooltip.tsx index dd6e8d678..bea6ee183 100644 --- a/ui-parts/tooltip/stories/story-tooltip.tsx +++ b/ui-parts/tooltip/stories/story-tooltip.tsx @@ -1,13 +1,18 @@ /* eslint-disable react/jsx-no-leaked-render */ -import type { ReactElement } from 'react' +import type { ReactElement } from 'react' -import type { StoryTooltipProps } from './interfaces.js' +import type { StoryTooltipProps } from './interfaces.js' -import { Tooltip } from '@atls-ui-parts/tooltip' +import { Tooltip } from '@atls-ui-parts/tooltip' -import { storyTriggerStyles } from './styles.css.js' -import { storyContainerStyles } from './styles.css.js' +import { storyContainerAppearanceStyles } from './styles.css.js' +import { storyContainerShapeStyles } from './styles.css.js' +import { storyTriggerStyles } from './styles.css.js' + +const storyContainerClassName = [storyContainerAppearanceStyles, storyContainerShapeStyles].join( + ' ' +) export const StoryTooltip = ({ animated, @@ -15,16 +20,19 @@ export const StoryTooltip = ({ customContainer, offset, placement, + styledContainer, trigger, }: StoryTooltipProps): ReactElement => ( : undefined} + container={customContainer ?
: undefined} >
Trigger
diff --git a/ui-parts/tooltip/stories/styles.css.ts b/ui-parts/tooltip/stories/styles.css.ts index 6d8f6acd5..fac105679 100644 --- a/ui-parts/tooltip/stories/styles.css.ts +++ b/ui-parts/tooltip/stories/styles.css.ts @@ -1,9 +1,13 @@ import { style } from '@vanilla-extract/css' -export const storyContainerStyles = style({ +export const storyContainerAppearanceStyles = style({ + background: 'green', + color: 'white', +}) + +export const storyContainerShapeStyles = style({ width: '150px', height: '30px', - background: 'green', margin: 0, }) diff --git a/ui-parts/tooltip/stories/tooltip.stories.tsx b/ui-parts/tooltip/stories/tooltip.stories.tsx index 6b3519478..4277bcf72 100644 --- a/ui-parts/tooltip/stories/tooltip.stories.tsx +++ b/ui-parts/tooltip/stories/tooltip.stories.tsx @@ -24,6 +24,10 @@ const meta: Meta = { description: 'Свой контейнер', control: { type: 'boolean' }, }, + styledContainer: { + description: 'Стили дефолтного контейнера', + control: { type: 'boolean' }, + }, offset: { description: 'Офсет', control: { type: 'number' }, @@ -56,6 +60,7 @@ const meta: Meta = { animated: true, arrow: true, customContainer: false, + styledContainer: false, offset: 10, placement: 'top', trigger: 'click', @@ -67,3 +72,10 @@ export default meta export const Base: StoryObj = { render: StoryTooltip, } + +export const StyledContainer: StoryObj = { + args: { + styledContainer: true, + }, + render: StoryTooltip, +} diff --git a/yarn.lock b/yarn.lock index e6b9f8536..798f96e3d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1046,6 +1046,7 @@ __metadata: dependencies: "@atls-ui-parts/condition": "workspace:*" "@atls-ui-parts/layout": "workspace:*" + "@atls-ui-parts/theme": "workspace:*" "@atls-utils/use-float": "workspace:*" "@floating-ui/react": "npm:0.27.8" "@storybook/react": "npm:8.6.12"