@koslibs/components 1.2.0 → 1.4.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/components/Button/button.js +1 -0
  3. package/dist/components/Collapse/collapse.d.ts +91 -0
  4. package/dist/components/Collapse/collapse.js +103 -0
  5. package/dist/components/Collapse/index.d.ts +2 -0
  6. package/dist/components/Collapse/index.js +1 -0
  7. package/dist/components/Collapse/index.module.js +12 -0
  8. package/dist/components/Collapse/index_module.css +82 -0
  9. package/dist/components/Collapse/vars.css +6 -0
  10. package/dist/components/Modal/colors.module.js +5 -0
  11. package/dist/components/Modal/colors_module.css +10 -0
  12. package/dist/components/Modal/components/content/index.d.ts +15 -0
  13. package/dist/components/Modal/components/content/index.js +18 -0
  14. package/dist/components/Modal/components/content/index.module.js +5 -0
  15. package/dist/components/Modal/components/content/index_module.css +12 -0
  16. package/dist/components/Modal/components/controls/index.d.ts +56 -0
  17. package/dist/components/Modal/components/controls/index.js +23 -0
  18. package/dist/components/Modal/components/controls/index.module.js +19 -0
  19. package/dist/components/Modal/components/controls/index_module.css +52 -0
  20. package/dist/components/Modal/components/footer/index.d.ts +15 -0
  21. package/dist/components/Modal/components/footer/index.js +18 -0
  22. package/dist/components/Modal/components/footer/index.module.js +5 -0
  23. package/dist/components/Modal/components/footer/index_module.css +9 -0
  24. package/dist/components/Modal/components/header/index.d.ts +43 -0
  25. package/dist/components/Modal/components/header/index.js +53 -0
  26. package/dist/components/Modal/components/header/index.module.js +8 -0
  27. package/dist/components/Modal/components/header/index_module.css +31 -0
  28. package/dist/components/Modal/components/modal-surface/index.d.ts +4 -0
  29. package/dist/components/Modal/components/modal-surface/index.js +81 -0
  30. package/dist/components/Modal/context.d.ts +6 -0
  31. package/dist/components/Modal/context.js +3 -0
  32. package/dist/components/Modal/index.d.ts +10 -0
  33. package/dist/components/Modal/index.js +5 -0
  34. package/dist/components/Modal/index.module.js +15 -0
  35. package/dist/components/Modal/index_module.css +46 -0
  36. package/dist/components/Modal/modal.d.ts +10 -0
  37. package/dist/components/Modal/modal.js +13 -0
  38. package/dist/components/Modal/types.d.ts +41 -0
  39. package/dist/components/Modal/types.js +0 -0
  40. package/dist/components/Modal/utils/lock-scroll.d.ts +1 -0
  41. package/dist/components/Modal/utils/lock-scroll.js +31 -0
  42. package/dist/components/Modal/vars.css +9 -0
  43. package/dist/components/Popover/popover.js +9 -7
  44. package/dist/components/Popover/types.d.ts +3 -1
  45. package/dist/components/Portal/index.d.ts +2 -0
  46. package/dist/components/Portal/index.js +1 -0
  47. package/dist/components/Portal/portal.d.ts +2 -0
  48. package/dist/components/Portal/portal.js +19 -0
  49. package/dist/components/Portal/types.d.ts +18 -0
  50. package/dist/components/Portal/types.js +0 -0
  51. package/dist/components/Typography/shared.d.ts +9 -3
  52. package/dist/index.d.ts +6 -0
  53. package/dist/index.js +3 -0
  54. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # @koslibs/components
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#5](https://github.com/koslibs/components/pull/5) [`68d3460`](https://github.com/koslibs/components/commit/68d34608d599582acf4115d31f64fb0168213edb) Thanks [@holypower777](https://github.com/holypower777)! - Перенесён Modal из GullEye core-components с Header, Content, Footer и Controls.
8
+ Добавлены прямой импорт `@koslibs/components/Modal`, размеры 480/600/720/960/fullscreen,
9
+ управляемое закрытие, блокировка прокрутки и поддержка вложенных окон.
10
+ Docs содержат вкладки документации, Props, CSS-переменных и истории изменений,
11
+ а также примеры длинного контента и Popover внутри нативного dialog.
12
+ Блокировка прокрутки учитывает `scrollbar-gutter: stable`, чтобы контент страницы
13
+ не смещался из-за двойной компенсации места под скроллбар.
14
+
15
+ Modal синхронизирован с документацией Figma: типографика Header 20 px semibold /
16
+ 14 px regular, крестик 18 px в области 48 × 32 px, Header без нижнего и Footer
17
+ без верхнего отступа. В строковых Controls две Button с block=true делят ширину
18
+ одной строки поровну с учётом gap; column растягивает кнопки по ширине вертикально.
19
+
20
+ Убран `Header.onClose`: крестик вызывает общий `Modal.onClose` через внутренний
21
+ React Context. Вложенный Header использует обработчик ближайшего Modal;
22
+ обработчик больше не нужно передавать отдельно в заголовок.
23
+
24
+ Header, Content, Footer и Controls наследуют `Modal.dataTestId` с суффиксами
25
+ `-header`, `-content`, `-footer`, `-controls`. Явный dataTestId части имеет приоритет;
26
+ вложенные окна используют только свой базовый идентификатор.
27
+
28
+ Добавлен отдельный Portal с `getPortalContainer`, `immediateMount`, ref на контейнер
29
+ и немедленным монтированием по умолчанию (`immediateMount=true`). Значение false
30
+ позволяет дождаться DOM-контейнера из ref. Modal и Popover используют
31
+ общий Portal; прямой импорт доступен через `@koslibs/components/Portal`.
32
+
33
+ ## 1.3.0
34
+
35
+ ### Minor Changes
36
+
37
+ - [#4](https://github.com/koslibs/components/pull/4) [`b37f3b0`](https://github.com/koslibs/components/commit/b37f3b008be8ffea80908557c13ea77d6d55c792) Thanks [@holypower777](https://github.com/holypower777)! - Перенесён Collapse из core-components GullEye с отдельным импортом
38
+ `@koslibs/components/Collapse`, внутренним и внешним управлением, сохранением
39
+ содержимого, анимацией и поддержкой reduced motion. Проп `colors` убран:
40
+ оформление кнопки настраивается через CSS-переменные. Добавлены документация
41
+ с тремя вкладками, Playground и история компонента. Стрелка подключается
42
+ отдельным импортом из `@koslibs/icons`.
43
+
44
+ Подписи `collapsedLabel` и `expandedLabel` не имеют дефолтных значений.
45
+ Добавлены `showRightChevron` (по умолчанию `true`) и `showLeftChevron`
46
+ (по умолчанию `false`): можно независимо показывать шевроны или скрыть оба.
47
+ Левый шеврон смотрит вправо в закрытом состоянии и вниз в раскрытом,
48
+ правый сохраняет поворот вниз → вверх.
49
+
50
+ Комментарии публичных пропсов приведены к единому многострочному формату JSDoc
51
+ с отдельной строкой для `@default`.
52
+
3
53
  ## 1.2.0
4
54
 
5
55
  ### Minor Changes
@@ -76,6 +76,7 @@ const Button = /*#__PURE__*/ forwardRef(({ view = 'primary', shape = 'rectangula
76
76
  [colors_module.loading]: showLoader
77
77
  }, className),
78
78
  "data-test-id": dataTestId,
79
+ "data-block": block || void 0,
79
80
  type: type,
80
81
  disabled: disabled || showLoader,
81
82
  "aria-busy": showLoader,
@@ -0,0 +1,91 @@
1
+ import { type HTMLAttributes, type ReactNode } from 'react';
2
+ export type CollapseProps = Omit<HTMLAttributes<HTMLDivElement>, 'onTransitionEnd'> & {
3
+ /**
4
+ * Состояние controlled-компонента.
5
+ */
6
+ expanded?: boolean;
7
+ /**
8
+ * Начальное состояние uncontrolled-компонента.
9
+ * @default false
10
+ */
11
+ defaultExpanded?: boolean;
12
+ /**
13
+ * Подпись кнопки, когда содержимое скрыто.
14
+ */
15
+ collapsedLabel?: ReactNode;
16
+ /**
17
+ * Подпись кнопки, когда содержимое раскрыто.
18
+ */
19
+ expandedLabel?: ReactNode;
20
+ /**
21
+ * Показывать шеврон справа от подписи: вниз при закрытии, вверх при раскрытии.
22
+ * @default true
23
+ */
24
+ showRightChevron?: boolean;
25
+ /**
26
+ * Показывать шеврон слева от подписи: вправо при закрытии, вниз при раскрытии.
27
+ * @default false
28
+ */
29
+ showLeftChevron?: boolean;
30
+ /**
31
+ * Запрос изменения состояния. В controlled-режиме обновите expanded.
32
+ */
33
+ onExpandedChange?: (expanded: boolean) => void;
34
+ /**
35
+ * Завершение раскрытия/сворачивания; без анимации вызывается сразу.
36
+ */
37
+ onTransitionEnd?: (expanded: boolean) => void;
38
+ /**
39
+ * Дополнительный класс внутреннего контейнера содержимого.
40
+ */
41
+ expandedContentClassName?: string;
42
+ /**
43
+ * Идентификатор корневого элемента для автоматизированных тестов.
44
+ */
45
+ dataTestId?: string;
46
+ };
47
+ export declare const Collapse: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "onTransitionEnd"> & {
48
+ /**
49
+ * Состояние controlled-компонента.
50
+ */
51
+ expanded?: boolean;
52
+ /**
53
+ * Начальное состояние uncontrolled-компонента.
54
+ * @default false
55
+ */
56
+ defaultExpanded?: boolean;
57
+ /**
58
+ * Подпись кнопки, когда содержимое скрыто.
59
+ */
60
+ collapsedLabel?: ReactNode;
61
+ /**
62
+ * Подпись кнопки, когда содержимое раскрыто.
63
+ */
64
+ expandedLabel?: ReactNode;
65
+ /**
66
+ * Показывать шеврон справа от подписи: вниз при закрытии, вверх при раскрытии.
67
+ * @default true
68
+ */
69
+ showRightChevron?: boolean;
70
+ /**
71
+ * Показывать шеврон слева от подписи: вправо при закрытии, вниз при раскрытии.
72
+ * @default false
73
+ */
74
+ showLeftChevron?: boolean;
75
+ /**
76
+ * Запрос изменения состояния. В controlled-режиме обновите expanded.
77
+ */
78
+ onExpandedChange?: (expanded: boolean) => void;
79
+ /**
80
+ * Завершение раскрытия/сворачивания; без анимации вызывается сразу.
81
+ */
82
+ onTransitionEnd?: (expanded: boolean) => void;
83
+ /**
84
+ * Дополнительный класс внутреннего контейнера содержимого.
85
+ */
86
+ expandedContentClassName?: string;
87
+ /**
88
+ * Идентификатор корневого элемента для автоматизированных тестов.
89
+ */
90
+ dataTestId?: string;
91
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,103 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { ChevronDownIcon } from "@koslibs/icons/ChevronDownIcon";
3
+ import classnames from "classnames";
4
+ import { forwardRef, useId, useLayoutEffect, useRef, useState } from "react";
5
+ import index_module from "./index.module.js";
6
+ const Collapse = /*#__PURE__*/ forwardRef(({ expanded, defaultExpanded = false, collapsedLabel, expandedLabel, showRightChevron = true, showLeftChevron = false, onExpandedChange, onTransitionEnd, expandedContentClassName, dataTestId, className, children, ...restProps }, ref)=>{
7
+ const [expandedState, setExpandedState] = useState(defaultExpanded);
8
+ const isExpanded = expanded ?? expandedState;
9
+ const contentId = `collapse-${useId()}`;
10
+ const contentRef = useRef(null);
11
+ const innerRef = useRef(null);
12
+ const toggleRef = useRef(null);
13
+ const previousExpanded = useRef(isExpanded);
14
+ const pendingTransition = useRef(false);
15
+ const transitionCallback = useRef(onTransitionEnd);
16
+ const label = isExpanded ? expandedLabel || collapsedLabel : collapsedLabel || expandedLabel;
17
+ useLayoutEffect(()=>{
18
+ transitionCallback.current = onTransitionEnd;
19
+ }, [
20
+ onTransitionEnd
21
+ ]);
22
+ useLayoutEffect(()=>{
23
+ const content = contentRef.current;
24
+ if (!content) return;
25
+ if (!isExpanded && content.contains(content.ownerDocument.activeElement)) toggleRef.current?.focus();
26
+ content.inert = !isExpanded;
27
+ if (previousExpanded.current === isExpanded) return;
28
+ previousExpanded.current = isExpanded;
29
+ pendingTransition.current = true;
30
+ const transitionDuration = content.ownerDocument.defaultView?.getComputedStyle(content).transitionDuration;
31
+ if (innerRef.current?.scrollHeight === 0 || 0 === parseFloat(transitionDuration ?? '0')) {
32
+ pendingTransition.current = false;
33
+ transitionCallback.current?.(isExpanded);
34
+ }
35
+ }, [
36
+ isExpanded
37
+ ]);
38
+ const handleToggle = ()=>{
39
+ const nextExpanded = !isExpanded;
40
+ if (void 0 === expanded) setExpandedState(nextExpanded);
41
+ onExpandedChange?.(nextExpanded);
42
+ };
43
+ const handleTransitionEnd = (event)=>{
44
+ if (event.target === event.currentTarget && 'grid-template-rows' === event.propertyName && pendingTransition.current) {
45
+ pendingTransition.current = false;
46
+ transitionCallback.current?.(isExpanded);
47
+ }
48
+ };
49
+ return /*#__PURE__*/ jsxs("div", {
50
+ ...restProps,
51
+ ref: ref,
52
+ className: classnames(index_module.component, className),
53
+ "data-test-id": dataTestId,
54
+ children: [
55
+ label && /*#__PURE__*/ jsxs("button", {
56
+ ref: toggleRef,
57
+ type: "button",
58
+ className: index_module.toggle,
59
+ "aria-expanded": isExpanded,
60
+ "aria-controls": contentId,
61
+ onClick: handleToggle,
62
+ "data-test-id": dataTestId ? `${dataTestId}-toggle` : void 0,
63
+ children: [
64
+ showLeftChevron && /*#__PURE__*/ jsx(ChevronDownIcon, {
65
+ className: classnames(index_module.icon, index_module.leftIcon, {
66
+ [index_module.rotated]: isExpanded
67
+ }),
68
+ "aria-hidden": "true"
69
+ }),
70
+ /*#__PURE__*/ jsx("span", {
71
+ children: label
72
+ }),
73
+ showRightChevron && /*#__PURE__*/ jsx(ChevronDownIcon, {
74
+ className: classnames(index_module.icon, {
75
+ [index_module.rotated]: isExpanded
76
+ }),
77
+ "aria-hidden": "true"
78
+ })
79
+ ]
80
+ }),
81
+ /*#__PURE__*/ jsx("div", {
82
+ ref: contentRef,
83
+ id: contentId,
84
+ className: classnames(index_module.content, {
85
+ [index_module.expanded]: isExpanded
86
+ }),
87
+ "aria-hidden": !isExpanded,
88
+ "data-test-id": dataTestId ? `${dataTestId}-content` : void 0,
89
+ onTransitionEnd: handleTransitionEnd,
90
+ children: /*#__PURE__*/ jsx("div", {
91
+ className: index_module.clip,
92
+ children: /*#__PURE__*/ jsx("div", {
93
+ ref: innerRef,
94
+ className: expandedContentClassName,
95
+ children: children
96
+ })
97
+ })
98
+ })
99
+ ]
100
+ });
101
+ });
102
+ Collapse.displayName = 'Collapse';
103
+ export { Collapse };
@@ -0,0 +1,2 @@
1
+ export { Collapse } from './collapse.js';
2
+ export type { CollapseProps } from './collapse.js';
@@ -0,0 +1 @@
1
+ export { Collapse } from "./collapse.js";
@@ -0,0 +1,12 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-tPiInR",
4
+ content: "content-D8E_z9",
5
+ expanded: "expanded-rqGMOG",
6
+ clip: "clip-D3ydtQ",
7
+ toggle: "toggle-YA8uJB",
8
+ icon: "icon-wFeaQN",
9
+ rotated: "rotated-sRw5l2",
10
+ leftIcon: "leftIcon-PGZrVM"
11
+ };
12
+ export default index_module;
@@ -0,0 +1,82 @@
1
+ @import "../../styles/theme.css";
2
+ @import "./vars.css";
3
+
4
+ .component-tPiInR {
5
+ min-width: 0;
6
+ font-family: var(--font-primary);
7
+ }
8
+
9
+ .content-D8E_z9 {
10
+ visibility: hidden;
11
+ grid-template-rows: 0fr;
12
+ transition: grid-template-rows .2s, visibility 0s linear .2s;
13
+ display: grid;
14
+ }
15
+
16
+ .expanded-rqGMOG {
17
+ visibility: visible;
18
+ grid-template-rows: 1fr;
19
+ transition-delay: 0s;
20
+ }
21
+
22
+ .clip-D3ydtQ {
23
+ min-height: 0;
24
+ overflow: hidden;
25
+ }
26
+
27
+ .toggle-YA8uJB {
28
+ align-items: center;
29
+ gap: var(--size-4, 4px);
30
+ max-width: 100%;
31
+ padding: var(--size-8, 8px) 0;
32
+ color: var(--collapse-color);
33
+ font: inherit;
34
+ text-align: left;
35
+ overflow-wrap: anywhere;
36
+ cursor: pointer;
37
+ background: none;
38
+ border: 0;
39
+ margin: 0;
40
+ font-size: 13px;
41
+ line-height: 20px;
42
+ display: inline-flex;
43
+
44
+ &:hover {
45
+ color: var(--collapse-hover-color);
46
+ }
47
+
48
+ &:hover span {
49
+ text-underline-offset: 3px;
50
+ text-decoration: underline;
51
+ }
52
+
53
+ &:focus-visible {
54
+ outline: 2px solid var(--collapse-focus-color);
55
+ outline-offset: 2px;
56
+ border-radius: var(--border-radius-4, 4px);
57
+ }
58
+ }
59
+
60
+ .icon-wFeaQN {
61
+ flex-shrink: 0;
62
+ transition: transform .2s;
63
+ }
64
+
65
+ .rotated-sRw5l2 {
66
+ transform: rotate(180deg);
67
+ }
68
+
69
+ .leftIcon-PGZrVM {
70
+ transform: rotate(-90deg);
71
+
72
+ &.rotated-sRw5l2 {
73
+ transform: rotate(0);
74
+ }
75
+ }
76
+
77
+ @media (prefers-reduced-motion: reduce) {
78
+ .content-D8E_z9, .icon-wFeaQN {
79
+ transition: none;
80
+ }
81
+ }
82
+
@@ -0,0 +1,6 @@
1
+ :root {
2
+ --collapse-color: #1c1a18;
3
+ --collapse-hover-color: #686d63;
4
+ --collapse-focus-color: #7967f2;
5
+ }
6
+
@@ -0,0 +1,5 @@
1
+ import "./colors_module.css";
2
+ const colors_module = {
3
+ component: "component-NzhSoV"
4
+ };
5
+ export default colors_module;
@@ -0,0 +1,10 @@
1
+ .component-NzhSoV {
2
+ background-color: var(--modal-background-color);
3
+ color: var(--modal-color);
4
+
5
+ &::backdrop {
6
+ background-color: var(--modal-backdrop-color);
7
+ backdrop-filter: blur(var(--modal-backdrop-blur));
8
+ }
9
+ }
10
+
@@ -0,0 +1,15 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ export type ContentProps = HTMLAttributes<HTMLDivElement> & {
3
+ /**
4
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -content.
5
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
6
+ */
7
+ dataTestId?: string;
8
+ };
9
+ export declare const Content: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
10
+ /**
11
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -content.
12
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
13
+ */
14
+ dataTestId?: string;
15
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,18 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import classnames from "classnames";
3
+ import { forwardRef, useContext } from "react";
4
+ import { ModalContext } from "../../context.js";
5
+ import index_module from "./index.module.js";
6
+ const Content = /*#__PURE__*/ forwardRef(({ children, className, dataTestId, ...restProps }, ref)=>{
7
+ const { dataTestId: modalDataTestId } = useContext(ModalContext);
8
+ const testId = dataTestId ?? modalDataTestId;
9
+ return /*#__PURE__*/ jsx("div", {
10
+ ...restProps,
11
+ ref: ref,
12
+ className: classnames(index_module.component, className),
13
+ "data-test-id": testId ? `${testId}-content` : void 0,
14
+ children: children
15
+ });
16
+ });
17
+ Content.displayName = 'ModalContent';
18
+ export { Content };
@@ -0,0 +1,5 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-Xoedpj"
4
+ };
5
+ export default index_module;
@@ -0,0 +1,12 @@
1
+ .component-Xoedpj {
2
+ gap: var(--size-24, 24px);
3
+ min-height: 0;
4
+ padding: var(--modal-padding);
5
+ overscroll-behavior: contain;
6
+ overflow-wrap: anywhere;
7
+ flex-direction: column;
8
+ flex: auto;
9
+ display: flex;
10
+ overflow: auto;
11
+ }
12
+
@@ -0,0 +1,56 @@
1
+ import { type HTMLAttributes, type ReactNode } from 'react';
2
+ import React from 'react';
3
+ export type ControlsProps = HTMLAttributes<HTMLDivElement> & {
4
+ /**
5
+ * Основное действие, отображается после дополнительного.
6
+ */
7
+ primary?: ReactNode;
8
+ /**
9
+ * Дополнительное действие.
10
+ */
11
+ secondary?: ReactNode;
12
+ /**
13
+ * Выравнивание действий.
14
+ * В строковых раскладках block-кнопки делят свободную ширину поровну.
15
+ * В column кнопки занимают всю ширину и располагаются друг под другом.
16
+ * @default 'end'
17
+ */
18
+ layout?: 'start' | 'end' | 'center' | 'space-between' | 'column';
19
+ /**
20
+ * Расстояние между действиями.
21
+ * @default 12
22
+ */
23
+ gap?: 8 | 12 | 16 | 24;
24
+ /**
25
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -controls.
26
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
27
+ */
28
+ dataTestId?: string;
29
+ };
30
+ export declare const Controls: React.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
31
+ /**
32
+ * Основное действие, отображается после дополнительного.
33
+ */
34
+ primary?: ReactNode;
35
+ /**
36
+ * Дополнительное действие.
37
+ */
38
+ secondary?: ReactNode;
39
+ /**
40
+ * Выравнивание действий.
41
+ * В строковых раскладках block-кнопки делят свободную ширину поровну.
42
+ * В column кнопки занимают всю ширину и располагаются друг под другом.
43
+ * @default 'end'
44
+ */
45
+ layout?: "start" | "end" | "center" | "space-between" | "column";
46
+ /**
47
+ * Расстояние между действиями.
48
+ * @default 12
49
+ */
50
+ gap?: 8 | 12 | 16 | 24;
51
+ /**
52
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -controls.
53
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
54
+ */
55
+ dataTestId?: string;
56
+ } & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,23 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import classnames from "classnames";
3
+ import react, { forwardRef, useContext } from "react";
4
+ import { ModalContext } from "../../context.js";
5
+ import index_module from "./index.module.js";
6
+ const Controls = /*#__PURE__*/ forwardRef(({ primary, secondary, layout = 'end', gap = 12, className, children, dataTestId, ...restProps }, ref)=>{
7
+ const { dataTestId: modalDataTestId } = useContext(ModalContext);
8
+ const testId = dataTestId ?? modalDataTestId;
9
+ return /*#__PURE__*/ jsx("div", {
10
+ ...restProps,
11
+ ref: ref,
12
+ className: classnames(index_module.component, index_module[layout], index_module[`gap-${gap}`], className),
13
+ "data-test-id": testId ? `${testId}-controls` : void 0,
14
+ children: children ?? /*#__PURE__*/ jsxs(react.Fragment, {
15
+ children: [
16
+ secondary,
17
+ primary
18
+ ]
19
+ })
20
+ });
21
+ });
22
+ Controls.displayName = 'ModalControls';
23
+ export { Controls };
@@ -0,0 +1,19 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-IPNCFT",
4
+ column: "column-dBeQXP",
5
+ start: "start-ouHlcU",
6
+ end: "end-TYAvEX",
7
+ center: "center-I4ALjs",
8
+ "space-between": "space-between-OxpVhA",
9
+ spaceBetween: "space-between-OxpVhA",
10
+ "gap-8": "gap-8-xwhlts",
11
+ gap8: "gap-8-xwhlts",
12
+ "gap-12": "gap-12-IFyQQK",
13
+ gap12: "gap-12-IFyQQK",
14
+ "gap-16": "gap-16-iZpxeN",
15
+ gap16: "gap-16-iZpxeN",
16
+ "gap-24": "gap-24-eEhuId",
17
+ gap24: "gap-24-eEhuId"
18
+ };
19
+ export default index_module;
@@ -0,0 +1,52 @@
1
+ .component-IPNCFT {
2
+ flex-wrap: wrap;
3
+ align-items: center;
4
+ width: 100%;
5
+ display: flex;
6
+ }
7
+
8
+ .component-IPNCFT:not(.column-dBeQXP) > button[data-block="true"] {
9
+ flex: 1 1 0;
10
+ }
11
+
12
+ .start-ouHlcU {
13
+ justify-content: flex-start;
14
+ }
15
+
16
+ .end-TYAvEX {
17
+ justify-content: flex-end;
18
+ }
19
+
20
+ .center-I4ALjs {
21
+ justify-content: center;
22
+ }
23
+
24
+ .space-between-OxpVhA {
25
+ justify-content: space-between;
26
+ }
27
+
28
+ .column-dBeQXP {
29
+ flex-direction: column;
30
+ align-items: stretch;
31
+ }
32
+
33
+ .column-dBeQXP > button {
34
+ width: 100%;
35
+ }
36
+
37
+ .gap-8-xwhlts {
38
+ gap: var(--size-8, 8px);
39
+ }
40
+
41
+ .gap-12-IFyQQK {
42
+ gap: var(--size-12, 12px);
43
+ }
44
+
45
+ .gap-16-iZpxeN {
46
+ gap: var(--size-16, 16px);
47
+ }
48
+
49
+ .gap-24-eEhuId {
50
+ gap: var(--size-24, 24px);
51
+ }
52
+
@@ -0,0 +1,15 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ export type FooterProps = HTMLAttributes<HTMLDivElement> & {
3
+ /**
4
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -footer.
5
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
6
+ */
7
+ dataTestId?: string;
8
+ };
9
+ export declare const Footer: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
10
+ /**
11
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -footer.
12
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
13
+ */
14
+ dataTestId?: string;
15
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,18 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import classnames from "classnames";
3
+ import { forwardRef, useContext } from "react";
4
+ import { ModalContext } from "../../context.js";
5
+ import index_module from "./index.module.js";
6
+ const Footer = /*#__PURE__*/ forwardRef(({ children, className, dataTestId, ...restProps }, ref)=>{
7
+ const { dataTestId: modalDataTestId } = useContext(ModalContext);
8
+ const testId = dataTestId ?? modalDataTestId;
9
+ return /*#__PURE__*/ jsx("div", {
10
+ ...restProps,
11
+ ref: ref,
12
+ className: classnames(index_module.component, className),
13
+ "data-test-id": testId ? `${testId}-footer` : void 0,
14
+ children: children
15
+ });
16
+ });
17
+ Footer.displayName = 'ModalFooter';
18
+ export { Footer };
@@ -0,0 +1,5 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-ZDJl0C"
4
+ };
5
+ export default index_module;
@@ -0,0 +1,9 @@
1
+ .component-ZDJl0C {
2
+ justify-content: flex-end;
3
+ align-items: center;
4
+ gap: var(--size-12, 12px);
5
+ padding: 0 var(--modal-padding) var(--modal-padding);
6
+ flex-shrink: 0;
7
+ display: flex;
8
+ }
9
+