@snack-uikit/card 0.14.1 → 0.14.2-preview-3e824eee.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/README.md CHANGED
@@ -42,6 +42,9 @@ import { Card, SearchPrivate } from "@snack-uikit/card";
42
42
  | functionBadge | `ReactNode` | - | Вложенный FunctionBadge |
43
43
  | className | `string` | - | CSS-класс для элемента с контентом |
44
44
  | href | `string` | - | Ссылка карточки |
45
+ | onKeyDown | `KeyboardEventHandler<HTMLDivElement>` | - | Колбек нажатия клавиши клавиатуры |
46
+ | ref | `LegacyRef<HTMLDivElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
47
+ | key | `Key` | - | |
45
48
 
46
49
 
47
50
  [//]: DOCUMENTATION_SECTION_END
@@ -1,4 +1,4 @@
1
- import { MouseEvent, ReactElement, ReactNode } from 'react';
1
+ import { KeyboardEventHandler, MouseEvent, ReactElement, ReactNode } from 'react';
2
2
  import { PromoTagProps } from '@snack-uikit/promo-tag';
3
3
  import { WithSupportProps } from '@snack-uikit/utils';
4
4
  import { Size } from '../../types';
@@ -32,5 +32,40 @@ export type CardProps = WithSupportProps<{
32
32
  className?: string;
33
33
  /** Ссылка карточки */
34
34
  href?: string;
35
+ /** Колбек нажатия клавиши клавиатуры */
36
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
35
37
  }>;
36
- export declare function Card({ onClick, disabled, checked, outline, multipleSelection, size, children, header, footer, functionBadge, promoBadge, image, className, href, ...rest }: CardProps): import("react/jsx-runtime").JSX.Element;
38
+ export declare const Card: import("react").ForwardRefExoticComponent<{
39
+ 'data-test-id'?: string;
40
+ } & import("react").AriaAttributes & {
41
+ /** Управление состоянием интерактивности */
42
+ disabled?: boolean;
43
+ /** Управление состоянием выбран/не выбран */
44
+ checked?: boolean;
45
+ /** Управление состоянием наличия обводки */
46
+ outline?: boolean;
47
+ /** Отображение галочки для режима массового выделения карточек */
48
+ multipleSelection?: boolean;
49
+ /** Колбек на клик по карточке */
50
+ onClick?(e: MouseEvent<HTMLDivElement | HTMLAnchorElement>): void;
51
+ /** Размер */
52
+ size?: Size;
53
+ /** PromoBadge */
54
+ promoBadge?: Pick<PromoTagProps, "text" | "appearance"> | string;
55
+ /** Вложенный контент */
56
+ children?: ReactNode;
57
+ /** Вложенный Header */
58
+ header?: ReactElement<HeaderProps>;
59
+ /** Вложенный Footer */
60
+ footer?: ReactNode;
61
+ /** Вложенный Image */
62
+ image?: ReactNode;
63
+ /** Вложенный FunctionBadge */
64
+ functionBadge?: ReactNode;
65
+ /** CSS-класс для элемента с контентом */
66
+ className?: string;
67
+ /** Ссылка карточки */
68
+ href?: string;
69
+ /** Колбек нажатия клавиши клавиатуры */
70
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
71
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -16,9 +16,10 @@ var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
16
16
  Object.defineProperty(exports, "__esModule", {
17
17
  value: true
18
18
  });
19
- exports.Card = Card;
19
+ exports.Card = void 0;
20
20
  const jsx_runtime_1 = require("react/jsx-runtime");
21
21
  const classnames_1 = __importDefault(require("classnames"));
22
+ const merge_refs_1 = __importDefault(require("merge-refs"));
22
23
  const react_1 = require("react");
23
24
  const typography_1 = require("@snack-uikit/typography");
24
25
  const utils_1 = require("@snack-uikit/utils");
@@ -27,7 +28,7 @@ const context_1 = require("../../context");
27
28
  const helperComponents_1 = require("../../helperComponents");
28
29
  const constants_2 = require("./constants");
29
30
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
30
- function Card(_a) {
31
+ exports.Card = (0, react_1.forwardRef)((_a, ref) => {
31
32
  var {
32
33
  onClick,
33
34
  disabled = false,
@@ -42,9 +43,10 @@ function Card(_a) {
42
43
  promoBadge,
43
44
  image,
44
45
  className,
45
- href
46
+ href,
47
+ onKeyDown: onKeyDownProp
46
48
  } = _a,
47
- rest = __rest(_a, ["onClick", "disabled", "checked", "outline", "multipleSelection", "size", "children", "header", "footer", "functionBadge", "promoBadge", "image", "className", "href"]);
49
+ rest = __rest(_a, ["onClick", "disabled", "checked", "outline", "multipleSelection", "size", "children", "header", "footer", "functionBadge", "promoBadge", "image", "className", "href", "onKeyDown"]);
48
50
  const localDivRef = (0, react_1.useRef)(null);
49
51
  const localAnchorRef = (0, react_1.useRef)(null);
50
52
  const onKeyDown = (0, react_1.useCallback)(e => {
@@ -53,8 +55,9 @@ function Card(_a) {
53
55
  if (constants_2.TRIGGER_CLICK_KEY_CODES.includes(e.code) || e.key === ' ') {
54
56
  href ? (_a = localAnchorRef.current) === null || _a === void 0 ? void 0 : _a.click() : (_b = localDivRef.current) === null || _b === void 0 ? void 0 : _b.click();
55
57
  }
58
+ onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(e);
56
59
  }
57
- }, [href]);
60
+ }, [href, onKeyDownProp]);
58
61
  const supportProps = (0, utils_1.extractSupportProps)(rest);
59
62
  return (0, jsx_runtime_1.jsx)(context_1.CardContext.Provider, {
60
63
  value: {
@@ -62,7 +65,7 @@ function Card(_a) {
62
65
  disabled
63
66
  },
64
67
  children: (0, jsx_runtime_1.jsxs)("div", Object.assign({
65
- ref: localDivRef,
68
+ ref: (0, merge_refs_1.default)(ref, localDivRef),
66
69
  className: (0, classnames_1.default)(styles_module_scss_1.default.card, className)
67
70
  }, supportProps, {
68
71
  onClick: onClick,
@@ -111,4 +114,4 @@ function Card(_a) {
111
114
  })]
112
115
  }))
113
116
  });
114
- }
117
+ });
@@ -1,4 +1,4 @@
1
- import { MouseEvent, ReactElement, ReactNode } from 'react';
1
+ import { KeyboardEventHandler, MouseEvent, ReactElement, ReactNode } from 'react';
2
2
  import { PromoTagProps } from '@snack-uikit/promo-tag';
3
3
  import { WithSupportProps } from '@snack-uikit/utils';
4
4
  import { Size } from '../../types';
@@ -32,5 +32,40 @@ export type CardProps = WithSupportProps<{
32
32
  className?: string;
33
33
  /** Ссылка карточки */
34
34
  href?: string;
35
+ /** Колбек нажатия клавиши клавиатуры */
36
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
35
37
  }>;
36
- export declare function Card({ onClick, disabled, checked, outline, multipleSelection, size, children, header, footer, functionBadge, promoBadge, image, className, href, ...rest }: CardProps): import("react/jsx-runtime").JSX.Element;
38
+ export declare const Card: import("react").ForwardRefExoticComponent<{
39
+ 'data-test-id'?: string;
40
+ } & import("react").AriaAttributes & {
41
+ /** Управление состоянием интерактивности */
42
+ disabled?: boolean;
43
+ /** Управление состоянием выбран/не выбран */
44
+ checked?: boolean;
45
+ /** Управление состоянием наличия обводки */
46
+ outline?: boolean;
47
+ /** Отображение галочки для режима массового выделения карточек */
48
+ multipleSelection?: boolean;
49
+ /** Колбек на клик по карточке */
50
+ onClick?(e: MouseEvent<HTMLDivElement | HTMLAnchorElement>): void;
51
+ /** Размер */
52
+ size?: Size;
53
+ /** PromoBadge */
54
+ promoBadge?: Pick<PromoTagProps, "text" | "appearance"> | string;
55
+ /** Вложенный контент */
56
+ children?: ReactNode;
57
+ /** Вложенный Header */
58
+ header?: ReactElement<HeaderProps>;
59
+ /** Вложенный Footer */
60
+ footer?: ReactNode;
61
+ /** Вложенный Image */
62
+ image?: ReactNode;
63
+ /** Вложенный FunctionBadge */
64
+ functionBadge?: ReactNode;
65
+ /** CSS-класс для элемента с контентом */
66
+ className?: string;
67
+ /** Ссылка карточки */
68
+ href?: string;
69
+ /** Колбек нажатия клавиши клавиатуры */
70
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
71
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -11,7 +11,8 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import cn from 'classnames';
14
- import { useCallback, useRef } from 'react';
14
+ import mergeRefs from 'merge-refs';
15
+ import { forwardRef, useCallback, useRef, } from 'react';
15
16
  import { Typography } from '@snack-uikit/typography';
16
17
  import { extractSupportProps } from '@snack-uikit/utils';
17
18
  import { SIZE, TEST_IDS } from '../../constants';
@@ -19,8 +20,8 @@ import { CardContext } from '../../context';
19
20
  import { Check, FunctionBadgeWrapper, PromoBadge } from '../../helperComponents';
20
21
  import { TRIGGER_CLICK_KEY_CODES } from './constants';
21
22
  import styles from './styles.module.css';
22
- export function Card(_a) {
23
- var { onClick, disabled = false, checked, outline, multipleSelection = false, size = SIZE.M, children, header, footer, functionBadge, promoBadge, image, className, href } = _a, rest = __rest(_a, ["onClick", "disabled", "checked", "outline", "multipleSelection", "size", "children", "header", "footer", "functionBadge", "promoBadge", "image", "className", "href"]);
23
+ export const Card = forwardRef((_a, ref) => {
24
+ var { onClick, disabled = false, checked, outline, multipleSelection = false, size = SIZE.M, children, header, footer, functionBadge, promoBadge, image, className, href, onKeyDown: onKeyDownProp } = _a, rest = __rest(_a, ["onClick", "disabled", "checked", "outline", "multipleSelection", "size", "children", "header", "footer", "functionBadge", "promoBadge", "image", "className", "href", "onKeyDown"]);
24
25
  const localDivRef = useRef(null);
25
26
  const localAnchorRef = useRef(null);
26
27
  const onKeyDown = useCallback((e) => {
@@ -29,10 +30,11 @@ export function Card(_a) {
29
30
  if (TRIGGER_CLICK_KEY_CODES.includes(e.code) || e.key === ' ') {
30
31
  href ? (_a = localAnchorRef.current) === null || _a === void 0 ? void 0 : _a.click() : (_b = localDivRef.current) === null || _b === void 0 ? void 0 : _b.click();
31
32
  }
33
+ onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(e);
32
34
  }
33
- }, [href]);
35
+ }, [href, onKeyDownProp]);
34
36
  const supportProps = extractSupportProps(rest);
35
- return (_jsx(CardContext.Provider, { value: { size, disabled }, children: _jsxs("div", Object.assign({ ref: localDivRef, className: cn(styles.card, className) }, supportProps, { onClick: onClick, "data-disabled": disabled || undefined, "data-checked": checked || undefined, "data-outline": outline || undefined, "data-pointer": onClick ? true : undefined,
37
+ return (_jsx(CardContext.Provider, { value: { size, disabled }, children: _jsxs("div", Object.assign({ ref: mergeRefs(ref, localDivRef), className: cn(styles.card, className) }, supportProps, { onClick: onClick, "data-disabled": disabled || undefined, "data-checked": checked || undefined, "data-outline": outline || undefined, "data-pointer": onClick ? true : undefined,
36
38
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
37
39
  tabIndex: 0, onKeyDown: onKeyDown, children: [image, _jsxs("div", { className: styles.composition, tabIndex: -1, children: [href && (_jsx("a", { ref: localAnchorRef, "data-test-id": TEST_IDS.anchor, tabIndex: -1, href: href, className: styles.anchor, "aria-label": supportProps['aria-label'] })), !disabled && functionBadge && (_jsx(FunctionBadgeWrapper, { className: styles.functionBadgeWrapper, children: functionBadge })), _jsx("div", { className: styles.contentWrapper, children: _jsxs("div", { className: styles.content, "data-size": size, children: [header || null, children && (_jsx(Typography, { family: 'sans', size: size, purpose: 'body', className: styles.body, tag: 'div', children: children })), footer && _jsx("div", { className: styles.footer, children: footer })] }) }), promoBadge && _jsx(PromoBadge, Object.assign({}, (typeof promoBadge === 'string' ? { text: promoBadge } : promoBadge)))] }), checked && multipleSelection && _jsx(Check, { className: styles.check })] })) }));
38
- }
40
+ });
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Card",
7
- "version": "0.14.1",
7
+ "version": "0.14.2-preview-3e824eee.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -39,13 +39,14 @@
39
39
  "@snack-uikit/button": "0.19.1",
40
40
  "@snack-uikit/icon-predefined": "0.7.0",
41
41
  "@snack-uikit/icons": "0.24.0",
42
- "@snack-uikit/list": "0.21.0",
42
+ "@snack-uikit/list": "0.21.1-preview-3e824eee.0",
43
43
  "@snack-uikit/promo-tag": "0.6.0",
44
44
  "@snack-uikit/tag": "0.11.1",
45
45
  "@snack-uikit/truncate-string": "0.6.0",
46
46
  "@snack-uikit/typography": "0.8.0",
47
47
  "@snack-uikit/utils": "3.5.0",
48
- "classnames": "2.3.2"
48
+ "classnames": "2.3.2",
49
+ "merge-refs": "1.2.2"
49
50
  },
50
- "gitHead": "b7163c6f939105eb34cabec64c9e983ac7958c26"
51
+ "gitHead": "e03a2d793311385c56686433260ea6572c6fc823"
51
52
  }
@@ -1,5 +1,15 @@
1
1
  import cn from 'classnames';
2
- import { KeyboardEvent, MouseEvent, ReactElement, ReactNode, useCallback, useRef } from 'react';
2
+ import mergeRefs from 'merge-refs';
3
+ import {
4
+ forwardRef,
5
+ KeyboardEvent,
6
+ KeyboardEventHandler,
7
+ MouseEvent,
8
+ ReactElement,
9
+ ReactNode,
10
+ useCallback,
11
+ useRef,
12
+ } from 'react';
3
13
 
4
14
  import { PromoTagProps } from '@snack-uikit/promo-tag';
5
15
  import { Typography } from '@snack-uikit/typography';
@@ -42,94 +52,104 @@ export type CardProps = WithSupportProps<{
42
52
  className?: string;
43
53
  /** Ссылка карточки */
44
54
  href?: string;
55
+ /** Колбек нажатия клавиши клавиатуры */
56
+ onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
45
57
  }>;
46
58
 
47
- export function Card({
48
- onClick,
49
- disabled = false,
50
- checked,
51
- outline,
52
- multipleSelection = false,
53
- size = SIZE.M,
54
- children,
55
- header,
56
- footer,
57
- functionBadge,
58
- promoBadge,
59
- image,
60
- className,
61
- href,
62
- ...rest
63
- }: CardProps) {
64
- const localDivRef = useRef<HTMLDivElement>(null);
65
- const localAnchorRef = useRef<HTMLAnchorElement>(null);
59
+ export const Card = forwardRef<HTMLDivElement, CardProps>(
60
+ (
61
+ {
62
+ onClick,
63
+ disabled = false,
64
+ checked,
65
+ outline,
66
+ multipleSelection = false,
67
+ size = SIZE.M,
68
+ children,
69
+ header,
70
+ footer,
71
+ functionBadge,
72
+ promoBadge,
73
+ image,
74
+ className,
75
+ href,
76
+ onKeyDown: onKeyDownProp,
77
+ ...rest
78
+ },
79
+ ref,
80
+ ) => {
81
+ const localDivRef = useRef<HTMLDivElement>(null);
82
+ const localAnchorRef = useRef<HTMLAnchorElement>(null);
83
+
84
+ const onKeyDown = useCallback(
85
+ (e: KeyboardEvent<HTMLDivElement>) => {
86
+ if (e.target === localDivRef.current) {
87
+ if (TRIGGER_CLICK_KEY_CODES.includes(e.code) || e.key === ' ') {
88
+ href ? localAnchorRef.current?.click() : localDivRef.current?.click();
89
+ }
66
90
 
67
- const onKeyDown = useCallback(
68
- (e: KeyboardEvent<HTMLDivElement>) => {
69
- if (e.target === localDivRef.current) {
70
- if (TRIGGER_CLICK_KEY_CODES.includes(e.code) || e.key === ' ') {
71
- href ? localAnchorRef.current?.click() : localDivRef.current?.click();
91
+ onKeyDownProp?.(e);
72
92
  }
73
- }
74
- },
75
- [href],
76
- );
93
+ },
94
+ [href, onKeyDownProp],
95
+ );
77
96
 
78
- const supportProps = extractSupportProps(rest);
97
+ const supportProps = extractSupportProps(rest);
79
98
 
80
- return (
81
- <CardContext.Provider value={{ size, disabled }}>
82
- {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
83
- <div
84
- ref={localDivRef}
85
- className={cn(styles.card, className)}
86
- {...supportProps}
87
- onClick={onClick}
88
- data-disabled={disabled || undefined}
89
- data-checked={checked || undefined}
90
- data-outline={outline || undefined}
91
- data-pointer={onClick ? true : undefined}
92
- // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
93
- tabIndex={0}
94
- onKeyDown={onKeyDown}
95
- >
96
- {image}
99
+ return (
100
+ <CardContext.Provider value={{ size, disabled }}>
101
+ {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
102
+ <div
103
+ ref={mergeRefs(ref, localDivRef)}
104
+ className={cn(styles.card, className)}
105
+ {...supportProps}
106
+ onClick={onClick}
107
+ data-disabled={disabled || undefined}
108
+ data-checked={checked || undefined}
109
+ data-outline={outline || undefined}
110
+ data-pointer={onClick ? true : undefined}
111
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
112
+ tabIndex={0}
113
+ onKeyDown={onKeyDown}
114
+ >
115
+ {image}
97
116
 
98
- <div className={styles.composition} tabIndex={-1}>
99
- {href && (
100
- <a
101
- ref={localAnchorRef}
102
- data-test-id={TEST_IDS.anchor}
103
- tabIndex={-1}
104
- href={href}
105
- className={styles.anchor}
106
- aria-label={supportProps['aria-label'] as string}
107
- />
108
- )}
117
+ <div className={styles.composition} tabIndex={-1}>
118
+ {href && (
119
+ <a
120
+ ref={localAnchorRef}
121
+ data-test-id={TEST_IDS.anchor}
122
+ tabIndex={-1}
123
+ href={href}
124
+ className={styles.anchor}
125
+ aria-label={supportProps['aria-label'] as string}
126
+ />
127
+ )}
109
128
 
110
- {!disabled && functionBadge && (
111
- <FunctionBadgeWrapper className={styles.functionBadgeWrapper}>{functionBadge}</FunctionBadgeWrapper>
112
- )}
129
+ {!disabled && functionBadge && (
130
+ <FunctionBadgeWrapper className={styles.functionBadgeWrapper}>{functionBadge}</FunctionBadgeWrapper>
131
+ )}
113
132
 
114
- <div className={styles.contentWrapper}>
115
- <div className={styles.content} data-size={size}>
116
- {header || null}
133
+ <div className={styles.contentWrapper}>
134
+ <div className={styles.content} data-size={size}>
135
+ {header || null}
117
136
 
118
- {children && (
119
- <Typography family='sans' size={size} purpose='body' className={styles.body} tag='div'>
120
- {children}
121
- </Typography>
122
- )}
137
+ {children && (
138
+ <Typography family='sans' size={size} purpose='body' className={styles.body} tag='div'>
139
+ {children}
140
+ </Typography>
141
+ )}
123
142
 
124
- {footer && <div className={styles.footer}>{footer}</div>}
143
+ {footer && <div className={styles.footer}>{footer}</div>}
144
+ </div>
125
145
  </div>
146
+
147
+ {promoBadge && <PromoBadge {...(typeof promoBadge === 'string' ? { text: promoBadge } : promoBadge)} />}
126
148
  </div>
127
149
 
128
- {promoBadge && <PromoBadge {...(typeof promoBadge === 'string' ? { text: promoBadge } : promoBadge)} />}
150
+ {checked && multipleSelection && <Check className={styles.check} />}
129
151
  </div>
130
-
131
- {checked && multipleSelection && <Check className={styles.check} />}
132
- </div>
133
- </CardContext.Provider>
134
- );
135
- }
152
+ </CardContext.Provider>
153
+ );
154
+ },
155
+ );