@cloud-ru/ds-tooltip 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/README.md +170 -0
- package/dist/cjs/components/QuestionTooltip/QuestionTooltip.d.ts +6 -0
- package/dist/cjs/components/QuestionTooltip/QuestionTooltip.js +26 -0
- package/dist/cjs/components/QuestionTooltip/index.d.ts +2 -0
- package/dist/cjs/components/QuestionTooltip/index.js +18 -0
- package/dist/cjs/components/QuestionTooltip/styles.module.css +39 -0
- package/dist/cjs/components/QuestionTooltip/types.d.ts +19 -0
- package/dist/cjs/components/QuestionTooltip/types.js +2 -0
- package/dist/cjs/components/Tooltip/Tooltip.d.ts +16 -0
- package/dist/cjs/components/Tooltip/Tooltip.js +20 -0
- package/dist/cjs/components/Tooltip/index.d.ts +1 -0
- package/dist/cjs/components/Tooltip/index.js +17 -0
- package/dist/cjs/components/Tooltip/styles.module.css +38 -0
- package/dist/cjs/components/WithTooltip/WithTooltip.d.ts +9 -0
- package/dist/cjs/components/WithTooltip/WithTooltip.js +11 -0
- package/dist/cjs/components/WithTooltip/index.d.ts +1 -0
- package/dist/cjs/components/WithTooltip/index.js +17 -0
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/index.js +19 -0
- package/dist/cjs/constants.d.ts +10 -0
- package/dist/cjs/constants.js +13 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/style.css +77 -0
- package/dist/cjs/types.d.ts +5 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/utils.d.ts +2 -0
- package/dist/cjs/utils.js +15 -0
- package/dist/esm/components/QuestionTooltip/QuestionTooltip.d.ts +6 -0
- package/dist/esm/components/QuestionTooltip/QuestionTooltip.js +20 -0
- package/dist/esm/components/QuestionTooltip/index.d.ts +2 -0
- package/dist/esm/components/QuestionTooltip/index.js +2 -0
- package/dist/esm/components/QuestionTooltip/styles.module.css +39 -0
- package/dist/esm/components/QuestionTooltip/types.d.ts +19 -0
- package/dist/esm/components/QuestionTooltip/types.js +1 -0
- package/dist/esm/components/Tooltip/Tooltip.d.ts +16 -0
- package/dist/esm/components/Tooltip/Tooltip.js +13 -0
- package/dist/esm/components/Tooltip/index.d.ts +1 -0
- package/dist/esm/components/Tooltip/index.js +1 -0
- package/dist/esm/components/Tooltip/styles.module.css +38 -0
- package/dist/esm/components/WithTooltip/WithTooltip.d.ts +9 -0
- package/dist/esm/components/WithTooltip/WithTooltip.js +8 -0
- package/dist/esm/components/WithTooltip/index.d.ts +1 -0
- package/dist/esm/components/WithTooltip/index.js +1 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.js +3 -0
- package/dist/esm/constants.d.ts +10 -0
- package/dist/esm/constants.js +10 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/style.css +77 -0
- package/dist/esm/types.d.ts +5 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils.d.ts +2 -0
- package/dist/esm/utils.js +12 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +44 -0
- package/src/components/QuestionTooltip/QuestionTooltip.tsx +59 -0
- package/src/components/QuestionTooltip/index.ts +2 -0
- package/src/components/QuestionTooltip/styles.module.scss +51 -0
- package/src/components/QuestionTooltip/types.ts +20 -0
- package/src/components/Tooltip/Tooltip.tsx +69 -0
- package/src/components/Tooltip/index.ts +1 -0
- package/src/components/Tooltip/styles.module.scss +41 -0
- package/src/components/WithTooltip/WithTooltip.tsx +16 -0
- package/src/components/WithTooltip/index.ts +1 -0
- package/src/components/index.ts +3 -0
- package/src/constants.ts +11 -0
- package/src/index.ts +5 -0
- package/src/types.ts +7 -0
- package/src/utils.ts +14 -0
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cloud-ru/ds-tooltip",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Пакет подсказок — компонент Tooltip для произвольного триггера и QuestionTooltip с иконкой «?» для полей форм и сложной терминологии.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/cloud-ru-tech/snack-v2.git",
|
|
8
|
+
"directory": "packages/tooltip"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/cloud-ru-tech/snack-v2/tree/master/packages/tooltip",
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"author": "Anna Kozlova <apkozlova@cloud.ru>",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/cjs/index.js",
|
|
15
|
+
"module": "./dist/esm/index.js",
|
|
16
|
+
"types": "./dist/esm/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"source": "./src/index.ts",
|
|
20
|
+
"types": "./dist/esm/index.d.ts",
|
|
21
|
+
"import": "./dist/esm/index.js",
|
|
22
|
+
"require": "./dist/cjs/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"./CHANGELOG.md",
|
|
29
|
+
"./LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"sideEffects": [
|
|
32
|
+
"*.css",
|
|
33
|
+
"**/*.css"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"classnames": "^2.5.1",
|
|
37
|
+
"@cloud-ru/ds-icons": "^1.0.0",
|
|
38
|
+
"@cloud-ru/ds-utils": "^1.0.0",
|
|
39
|
+
"@cloud-ru/ds-popover-private": "^1.0.0"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { QuestionSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
2
|
+
import { TRIGGER } from '@cloud-ru/ds-popover-private';
|
|
3
|
+
import { useUncontrolledProp } from '@cloud-ru/ds-utils';
|
|
4
|
+
import cn from 'classnames';
|
|
5
|
+
import { RefObject } from 'react';
|
|
6
|
+
|
|
7
|
+
import { SIZE, TEST_IDS } from '../../constants';
|
|
8
|
+
import { getIconSize } from '../../utils';
|
|
9
|
+
import { Tooltip } from '../Tooltip';
|
|
10
|
+
import styles from './styles.module.scss';
|
|
11
|
+
import { QuestionTooltipProps } from './types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* QuestionTooltip — иконка «?» с тултипом-popover для подсказок к полям форм.
|
|
15
|
+
* Поверхность одна на всех раскладках (по договорённости с дизайном mobile не свапается на BottomSheet).
|
|
16
|
+
*/
|
|
17
|
+
export function QuestionTooltip({
|
|
18
|
+
tip,
|
|
19
|
+
triggerLabel = 'Подсказка',
|
|
20
|
+
trigger = TRIGGER.Hover,
|
|
21
|
+
className,
|
|
22
|
+
tooltipClassname,
|
|
23
|
+
open,
|
|
24
|
+
onOpenChange,
|
|
25
|
+
tabIndex = 0,
|
|
26
|
+
size = SIZE.XS,
|
|
27
|
+
triggerRef,
|
|
28
|
+
...rest
|
|
29
|
+
}: QuestionTooltipProps) {
|
|
30
|
+
const [isOpen, setIsOpen] = useUncontrolledProp(open, false, onOpenChange);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Tooltip
|
|
34
|
+
tip={tip}
|
|
35
|
+
className={tooltipClassname}
|
|
36
|
+
triggerClassName={styles.questionTooltipTrigger}
|
|
37
|
+
open={isOpen}
|
|
38
|
+
onOpenChange={setIsOpen}
|
|
39
|
+
trigger={trigger}
|
|
40
|
+
{...rest}
|
|
41
|
+
>
|
|
42
|
+
<button
|
|
43
|
+
type='button'
|
|
44
|
+
aria-label={triggerLabel}
|
|
45
|
+
data-opened={isOpen}
|
|
46
|
+
data-trigger={trigger}
|
|
47
|
+
tabIndex={tabIndex}
|
|
48
|
+
className={cn(styles.button, className)}
|
|
49
|
+
data-size={size}
|
|
50
|
+
data-test-id={TEST_IDS.questionTooltip.triggerOpen}
|
|
51
|
+
// Ref ведёт на саму кнопку, а не на span-обёртку popover'а: потребителю
|
|
52
|
+
// нужен настоящий триггер (позиционирование, фокус).
|
|
53
|
+
ref={triggerRef as RefObject<HTMLButtonElement>}
|
|
54
|
+
>
|
|
55
|
+
<QuestionSVG size={getIconSize(size)} />
|
|
56
|
+
</button>
|
|
57
|
+
</Tooltip>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
|
|
3
|
+
$sizes: 'xs', 's';
|
|
4
|
+
|
|
5
|
+
.questionTooltipTrigger {
|
|
6
|
+
position: relative;
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.button {
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
|
|
15
|
+
position: relative;
|
|
16
|
+
|
|
17
|
+
display: inline-flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
border: none;
|
|
24
|
+
|
|
25
|
+
font: inherit;
|
|
26
|
+
color: base.$sn-theme-color-available-version-textTertiary;
|
|
27
|
+
|
|
28
|
+
background: transparent;
|
|
29
|
+
|
|
30
|
+
&:focus-visible {
|
|
31
|
+
outline: base.$sn-primitive-strokeWeight-strokeSemiBold solid base.$sn-theme-color-available-complementary;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&:active {
|
|
35
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@media (hover: hover) {
|
|
39
|
+
// `:not(:active)` — иначе hover перебивает pressed и мышью он недостижим.
|
|
40
|
+
&:hover:not(:active) {
|
|
41
|
+
color: base.$sn-theme-color-available-version-textSecondary;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@each $size in $sizes {
|
|
46
|
+
&[data-size='#{$size}'] {
|
|
47
|
+
width: base.simple-var(base.$sn-density, 'size', 'icon', $size);
|
|
48
|
+
height: base.simple-var(base.$sn-density, 'size', 'icon', $size);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Size } from '../../types';
|
|
2
|
+
import { TooltipProps } from '../Tooltip';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* QuestionTooltip: иконка «?» с тултипом-popover. Поверхность одна на всех раскладках.
|
|
6
|
+
* `tooltipClassname` применяется к контейнеру подсказки.
|
|
7
|
+
*/
|
|
8
|
+
export type QuestionTooltipProps = TooltipProps & {
|
|
9
|
+
/** CSS-класс контейнера подсказки */
|
|
10
|
+
tooltipClassname?: string;
|
|
11
|
+
/** Доступное имя для иконки-триггера */
|
|
12
|
+
triggerLabel?: string;
|
|
13
|
+
/** Tab index для кнопки-триггера */
|
|
14
|
+
tabIndex?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Размер
|
|
17
|
+
* @default xs
|
|
18
|
+
*/
|
|
19
|
+
size?: Size;
|
|
20
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { PLACEMENT, PopoverPrivate, PopoverPrivateProps, TRIGGER } from '@cloud-ru/ds-popover-private';
|
|
2
|
+
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
+
import cn from 'classnames';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
import styles from './styles.module.scss';
|
|
7
|
+
|
|
8
|
+
export type TooltipProps = WithSupportProps<{
|
|
9
|
+
/** Содержимое тултипа (текст или разметка) */
|
|
10
|
+
tip: ReactNode;
|
|
11
|
+
/** Отключение ограничения ширины тултипа @default false */
|
|
12
|
+
disableMaxWidth?: boolean;
|
|
13
|
+
}> &
|
|
14
|
+
Pick<
|
|
15
|
+
PopoverPrivateProps,
|
|
16
|
+
| 'className'
|
|
17
|
+
| 'triggerClassName'
|
|
18
|
+
| 'offset'
|
|
19
|
+
| 'open'
|
|
20
|
+
| 'onOpenChange'
|
|
21
|
+
| 'hoverDelayOpen'
|
|
22
|
+
| 'hoverDelayClose'
|
|
23
|
+
| 'triggerRef'
|
|
24
|
+
| 'disableSpanWrapper'
|
|
25
|
+
| 'fallbackPlacements'
|
|
26
|
+
| 'closeOnPopstate'
|
|
27
|
+
> &
|
|
28
|
+
Partial<Pick<PopoverPrivateProps, 'trigger' | 'placement' | 'children'>>;
|
|
29
|
+
|
|
30
|
+
export const DEFAULT_FALLBACK_PLACEMENTS = [PLACEMENT.Top, PLACEMENT.Right, PLACEMENT.Bottom, PLACEMENT.Left];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Tooltip — всплывающая подсказка при наведении.
|
|
34
|
+
* Стили и анатомия (отступы, скругления, макс. ширина) из @cloud-ru/ds-figma-variables.
|
|
35
|
+
* DOM повторяет структуру из Figma: корневой контейнер и слои (фон, контейнер контента, указатель) с position: absolute.
|
|
36
|
+
*/
|
|
37
|
+
export function Tooltip({
|
|
38
|
+
children,
|
|
39
|
+
tip,
|
|
40
|
+
placement = PLACEMENT.Top,
|
|
41
|
+
trigger = TRIGGER.HoverAndFocusVisible,
|
|
42
|
+
hoverDelayOpen = 0,
|
|
43
|
+
hoverDelayClose = 0,
|
|
44
|
+
triggerClassName,
|
|
45
|
+
disableMaxWidth = false,
|
|
46
|
+
...otherProps
|
|
47
|
+
}: TooltipProps) {
|
|
48
|
+
return (
|
|
49
|
+
<PopoverPrivate
|
|
50
|
+
trigger={trigger}
|
|
51
|
+
placement={placement}
|
|
52
|
+
hasArrow
|
|
53
|
+
arrowContainerClassName={styles.pointerWrapper}
|
|
54
|
+
arrowElementClassName={styles.pointerShape}
|
|
55
|
+
hoverDelayOpen={hoverDelayOpen}
|
|
56
|
+
hoverDelayClose={hoverDelayClose}
|
|
57
|
+
fallbackPlacements={DEFAULT_FALLBACK_PLACEMENTS}
|
|
58
|
+
triggerClassName={cn(styles.triggerClassName, triggerClassName)}
|
|
59
|
+
popoverContent={
|
|
60
|
+
<div className={styles.tooltipContainer} data-disable-max-width={disableMaxWidth} role='tooltip'>
|
|
61
|
+
{tip}
|
|
62
|
+
</div>
|
|
63
|
+
}
|
|
64
|
+
{...otherProps}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</PopoverPrivate>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Tooltip';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/tooltip.module' as tooltip;
|
|
3
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/popover.module' as popover;
|
|
4
|
+
|
|
5
|
+
.triggerClassName {
|
|
6
|
+
--offset: #{base.simple-var(popover.$popover, 'anatomy', 'privatePopover', 'offset')};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.tooltipContainer {
|
|
10
|
+
@include base.composite-var(tooltip.$tooltip, 'anatomy', 'container');
|
|
11
|
+
@include base.composite-var(base.$base-styles, 'sn', 'regular', 'body', 's');
|
|
12
|
+
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
|
|
18
|
+
color: base.$sn-theme-color-available-inversion-textMain;
|
|
19
|
+
overflow-wrap: break-word;
|
|
20
|
+
|
|
21
|
+
background: base.$sn-theme-color-invertNeutral-background2Level;
|
|
22
|
+
|
|
23
|
+
&[data-disable-max-width='true'] {
|
|
24
|
+
max-width: calc(100vw - #{base.$sn-primitive-dimension-16});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Отступ указателя от угла держит кламп floating-ui (`arrow({ padding })`), паддингом его дублировать нельзя.
|
|
29
|
+
.pointerWrapper {
|
|
30
|
+
position: absolute;
|
|
31
|
+
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
|
|
36
|
+
color: base.$sn-theme-color-invertNeutral-background2Level;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.pointerShape {
|
|
40
|
+
fill: currentcolor;
|
|
41
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Tooltip, TooltipProps } from '../Tooltip';
|
|
2
|
+
|
|
3
|
+
type WithTooltipProps = {
|
|
4
|
+
/** Настройки для тултипа */
|
|
5
|
+
tooltip?: Omit<TooltipProps, 'children'>;
|
|
6
|
+
/** Триггер поповера (подробнее в TooltipProps) */
|
|
7
|
+
children: TooltipProps['children'];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function WithTooltip({ tooltip, children }: WithTooltipProps) {
|
|
11
|
+
if (!tooltip?.tip) {
|
|
12
|
+
return <>{children}</>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return <Tooltip {...tooltip}>{children}</Tooltip>;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './WithTooltip';
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const SIZE = {
|
|
2
|
+
XS: 'xs',
|
|
3
|
+
S: 's',
|
|
4
|
+
} as const;
|
|
5
|
+
|
|
6
|
+
/** Стабильные `data-test-id` на внутренних слотах, которые компонент ставит сам. */
|
|
7
|
+
export const TEST_IDS = {
|
|
8
|
+
questionTooltip: {
|
|
9
|
+
triggerOpen: 'question-tooltip-trigger',
|
|
10
|
+
},
|
|
11
|
+
} as const;
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
package/src/utils.ts
ADDED