@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
@@ -0,0 +1,43 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ export type HeaderProps = Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'onClose' | 'children'> & {
3
+ /**
4
+ * Заголовок окна.
5
+ */
6
+ title?: string;
7
+ /**
8
+ * Описание под заголовком.
9
+ */
10
+ subtitle?: string;
11
+ /**
12
+ * Показывать кнопку закрытия.
13
+ * Кнопка вызывает onClose ближайшего Modal.
14
+ * @default true
15
+ */
16
+ hasCloser?: boolean;
17
+ /**
18
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -header.
19
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
20
+ */
21
+ dataTestId?: string;
22
+ };
23
+ export declare const Header: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "title" | "children" | "onClose"> & {
24
+ /**
25
+ * Заголовок окна.
26
+ */
27
+ title?: string;
28
+ /**
29
+ * Описание под заголовком.
30
+ */
31
+ subtitle?: string;
32
+ /**
33
+ * Показывать кнопку закрытия.
34
+ * Кнопка вызывает onClose ближайшего Modal.
35
+ * @default true
36
+ */
37
+ hasCloser?: boolean;
38
+ /**
39
+ * Базовый идентификатор для автоматизированных тестов с суффиксом -header.
40
+ * По умолчанию наследуется от ближайшего Modal; явно заданный имеет приоритет.
41
+ */
42
+ dataTestId?: string;
43
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,53 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { CrossHeavyMIcon } from "@koslibs/icons/CrossHeavyMIcon";
3
+ import classnames from "classnames";
4
+ import { forwardRef, useContext } from "react";
5
+ import { Button } from "../../../Button/index.js";
6
+ import { TypographyText } from "../../../Typography/index.js";
7
+ import { ModalContext } from "../../context.js";
8
+ import index_module from "./index.module.js";
9
+ const Header = /*#__PURE__*/ forwardRef(({ title, subtitle, hasCloser = true, className, dataTestId, ...restProps }, ref)=>{
10
+ const { onClose, dataTestId: modalDataTestId } = useContext(ModalContext);
11
+ const testId = dataTestId ?? modalDataTestId;
12
+ const handleClick = ()=>{
13
+ onClose?.();
14
+ };
15
+ return /*#__PURE__*/ jsxs("div", {
16
+ ...restProps,
17
+ ref: ref,
18
+ className: classnames(index_module.component, className),
19
+ "data-test-id": testId ? `${testId}-header` : void 0,
20
+ children: [
21
+ /*#__PURE__*/ jsxs("div", {
22
+ className: index_module.content,
23
+ children: [
24
+ Boolean(title) && /*#__PURE__*/ jsx(TypographyText, {
25
+ size: 20,
26
+ weight: "semibold",
27
+ children: title
28
+ }),
29
+ Boolean(subtitle) && /*#__PURE__*/ jsx(TypographyText, {
30
+ size: 14,
31
+ color: "secondary",
32
+ children: subtitle
33
+ })
34
+ ]
35
+ }),
36
+ hasCloser && /*#__PURE__*/ jsx(Button, {
37
+ size: 32,
38
+ view: "transparent",
39
+ className: index_module.closer,
40
+ labelClassName: index_module.closerLabel,
41
+ "aria-label": "Закрыть окно",
42
+ onClick: handleClick,
43
+ children: /*#__PURE__*/ jsx(CrossHeavyMIcon, {
44
+ width: 18,
45
+ height: 18,
46
+ "aria-hidden": "true"
47
+ })
48
+ })
49
+ ]
50
+ });
51
+ });
52
+ Header.displayName = 'ModalHeader';
53
+ export { Header };
@@ -0,0 +1,8 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-sqEuYd",
4
+ content: "content-cnwKDB",
5
+ closer: "closer-odHjP5",
6
+ closerLabel: "closerLabel-r61y3R"
7
+ };
8
+ export default index_module;
@@ -0,0 +1,31 @@
1
+ .component-sqEuYd {
2
+ justify-content: space-between;
3
+ align-items: flex-start;
4
+ gap: var(--size-24, 24px);
5
+ padding: var(--modal-padding) var(--modal-padding) 0;
6
+ flex-shrink: 0;
7
+ display: flex;
8
+ }
9
+
10
+ .content-cnwKDB {
11
+ gap: var(--size-4, 4px);
12
+ overflow-wrap: anywhere;
13
+ flex-direction: column;
14
+ flex: 1;
15
+ min-width: 0;
16
+ display: flex;
17
+ }
18
+
19
+ .component-sqEuYd > .closer-odHjP5 {
20
+ flex-shrink: 0;
21
+ width: 48px;
22
+ min-width: 48px;
23
+ padding: 0;
24
+ }
25
+
26
+ .closerLabel-r61y3R {
27
+ justify-content: center;
28
+ align-items: center;
29
+ display: flex;
30
+ }
31
+
@@ -0,0 +1,4 @@
1
+ import type { ModalProps } from '../../types.js';
2
+ type SurfaceProps = Omit<ModalProps, 'open' | 'getPortalContainer'>;
3
+ export declare const ModalSurface: import("react").ForwardRefExoticComponent<SurfaceProps & import("react").RefAttributes<HTMLDialogElement>>;
4
+ export {};
@@ -0,0 +1,81 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import classnames from "classnames";
3
+ import { forwardRef, useCallback, useLayoutEffect, useMemo, useRef } from "react";
4
+ import { ModalContext } from "../../context.js";
5
+ import { lockScroll } from "../../utils/lock-scroll.js";
6
+ import colors_module from "../../colors.module.js";
7
+ import index_module from "../../index.module.js";
8
+ const ModalSurface = /*#__PURE__*/ forwardRef(({ onClose, size = 720, escapeKeyDown = true, backdropClick = true, lockScroll: shouldLockScroll = true, className, dataTestId, children, onPointerDown, onClick, ...restProps }, ref)=>{
9
+ const dialogRef = useRef(null);
10
+ const backdropPointerDown = useRef(false);
11
+ const mounted = useRef(false);
12
+ const contextValue = useMemo(()=>({
13
+ onClose,
14
+ dataTestId
15
+ }), [
16
+ onClose,
17
+ dataTestId
18
+ ]);
19
+ const mergedRef = useCallback((element)=>{
20
+ dialogRef.current = element;
21
+ if ('function' == typeof ref) ref(element);
22
+ else if (ref) ref.current = element;
23
+ }, [
24
+ ref
25
+ ]);
26
+ useLayoutEffect(()=>{
27
+ const dialog = dialogRef.current;
28
+ if (!dialog) return;
29
+ mounted.current = true;
30
+ if (!dialog.open) dialog.showModal();
31
+ return ()=>{
32
+ mounted.current = false;
33
+ dialog.close();
34
+ };
35
+ }, []);
36
+ useLayoutEffect(()=>{
37
+ const dialog = dialogRef.current;
38
+ if (dialog && shouldLockScroll) return lockScroll(dialog.ownerDocument);
39
+ }, [
40
+ shouldLockScroll
41
+ ]);
42
+ const isBackdrop = (event)=>{
43
+ const bounds = event.currentTarget.getBoundingClientRect();
44
+ return event.target === event.currentTarget && (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom);
45
+ };
46
+ const handleCancel = (event)=>{
47
+ event.stopPropagation();
48
+ event.preventDefault();
49
+ if (escapeKeyDown) onClose?.();
50
+ };
51
+ const handleClose = (event)=>{
52
+ event.stopPropagation();
53
+ if (mounted.current && !event.currentTarget.open) onClose?.();
54
+ };
55
+ const handlePointerDown = (event)=>{
56
+ onPointerDown?.(event);
57
+ backdropPointerDown.current = !event.defaultPrevented && isBackdrop(event);
58
+ };
59
+ const handleClick = (event)=>{
60
+ onClick?.(event);
61
+ const close = backdropPointerDown.current && isBackdrop(event);
62
+ backdropPointerDown.current = false;
63
+ if (backdropClick && close && !event.defaultPrevented) onClose?.();
64
+ };
65
+ return /*#__PURE__*/ jsx("dialog", {
66
+ ...restProps,
67
+ ref: mergedRef,
68
+ className: classnames(index_module.component, colors_module.component, index_module[`size-${size}`], className),
69
+ "data-test-id": dataTestId,
70
+ onCancel: handleCancel,
71
+ onClose: handleClose,
72
+ onPointerDown: handlePointerDown,
73
+ onClick: handleClick,
74
+ children: /*#__PURE__*/ jsx(ModalContext.Provider, {
75
+ value: contextValue,
76
+ children: children
77
+ })
78
+ });
79
+ });
80
+ ModalSurface.displayName = 'ModalSurface';
81
+ export { ModalSurface };
@@ -0,0 +1,6 @@
1
+ type ModalContextValue = {
2
+ onClose?: VoidFunction;
3
+ dataTestId?: string;
4
+ };
5
+ export declare const ModalContext: import("react").Context<ModalContextValue>;
6
+ export {};
@@ -0,0 +1,3 @@
1
+ import { createContext } from "react";
2
+ const ModalContext = createContext({});
3
+ export { ModalContext };
@@ -0,0 +1,10 @@
1
+ export { Modal, Modal as ModalComponent } from './modal.js';
2
+ export type { ModalProps } from './types.js';
3
+ export { Header, Header as ModalHeader } from './components/header/index.js';
4
+ export type { HeaderProps } from './components/header/index.js';
5
+ export { Content, Content as ModalContent } from './components/content/index.js';
6
+ export type { ContentProps } from './components/content/index.js';
7
+ export { Footer, Footer as ModalFooter } from './components/footer/index.js';
8
+ export type { FooterProps } from './components/footer/index.js';
9
+ export { Controls, Controls as ModalControls } from './components/controls/index.js';
10
+ export type { ControlsProps } from './components/controls/index.js';
@@ -0,0 +1,5 @@
1
+ export { Modal, Modal as ModalComponent } from "./modal.js";
2
+ export { Header, Header as ModalHeader } from "./components/header/index.js";
3
+ export { Content, Content as ModalContent } from "./components/content/index.js";
4
+ export { Footer, Footer as ModalFooter } from "./components/footer/index.js";
5
+ export { Controls, Controls as ModalControls } from "./components/controls/index.js";
@@ -0,0 +1,15 @@
1
+ import "./index_module.css";
2
+ const index_module = {
3
+ component: "component-kCkvk3",
4
+ "size-480": "size-480-fXx4Vl",
5
+ size480: "size-480-fXx4Vl",
6
+ "size-600": "size-600-X9nvTO",
7
+ size600: "size-600-X9nvTO",
8
+ "size-720": "size-720-_guzbs",
9
+ size720: "size-720-_guzbs",
10
+ "size-960": "size-960-I8vXpb",
11
+ size960: "size-960-I8vXpb",
12
+ "size-fullscreen": "size-fullscreen-exf2cb",
13
+ sizeFullscreen: "size-fullscreen-exf2cb"
14
+ };
15
+ export default index_module;
@@ -0,0 +1,46 @@
1
+ @import "../../styles/theme.css";
2
+ @import "./vars.css";
3
+
4
+ .component-kCkvk3 {
5
+ border-radius: var(--border-radius-12, 12px);
6
+ max-width: calc(100vw - var(--size-32, 32px));
7
+ max-height: calc(100dvh - var(--size-32, 32px));
8
+ box-sizing: border-box;
9
+ min-width: 0;
10
+ font-family: var(--font-primary);
11
+ box-shadow: var(--modal-shadow);
12
+ border: none;
13
+ margin: auto;
14
+ padding: 0;
15
+ overflow: hidden;
16
+
17
+ &[open] {
18
+ flex-direction: column;
19
+ display: flex;
20
+ }
21
+ }
22
+
23
+ .size-480-fXx4Vl {
24
+ width: 480px;
25
+ }
26
+
27
+ .size-600-X9nvTO {
28
+ width: 600px;
29
+ }
30
+
31
+ .size-720-_guzbs {
32
+ width: 720px;
33
+ }
34
+
35
+ .size-960-I8vXpb {
36
+ width: 960px;
37
+ }
38
+
39
+ .size-fullscreen-exf2cb {
40
+ border-radius: 0;
41
+ width: 100vw;
42
+ max-width: none;
43
+ height: 100dvh;
44
+ max-height: none;
45
+ }
46
+
@@ -0,0 +1,10 @@
1
+ export declare const Modal: import("react").ForwardRefExoticComponent<Omit<import("react").DialogHTMLAttributes<HTMLDialogElement>, "open" | "onClose" | "onCancel"> & {
2
+ open: boolean;
3
+ onClose?: VoidFunction;
4
+ size?: 480 | 600 | 720 | 960 | "fullscreen";
5
+ escapeKeyDown?: boolean;
6
+ backdropClick?: boolean;
7
+ lockScroll?: boolean;
8
+ getPortalContainer?: () => Element | null;
9
+ dataTestId?: string;
10
+ } & import("react").RefAttributes<HTMLDialogElement>>;
@@ -0,0 +1,13 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { Portal } from "../Portal/index.js";
4
+ import { ModalSurface } from "./components/modal-surface/index.js";
5
+ const Modal = /*#__PURE__*/ forwardRef(({ open, getPortalContainer, ...restProps }, ref)=>open ? /*#__PURE__*/ jsx(Portal, {
6
+ getPortalContainer: getPortalContainer,
7
+ children: /*#__PURE__*/ jsx(ModalSurface, {
8
+ ...restProps,
9
+ ref: ref
10
+ })
11
+ }) : null);
12
+ Modal.displayName = 'Modal';
13
+ export { Modal };
@@ -0,0 +1,41 @@
1
+ import type { DialogHTMLAttributes } from 'react';
2
+ export type ModalProps = Omit<DialogHTMLAttributes<HTMLDialogElement>, 'open' | 'onClose' | 'onCancel'> & {
3
+ /**
4
+ * Видимость окна. Закрытие запрашивается через onClose.
5
+ */
6
+ open: boolean;
7
+ /**
8
+ * Обработчик запроса закрытия. Обновите open в вызывающем компоненте.
9
+ * Вызывается в том числе кнопкой закрытия Header.
10
+ */
11
+ onClose?: VoidFunction;
12
+ /**
13
+ * Ширина в пикселях или окно на весь экран.
14
+ * @default 720
15
+ */
16
+ size?: 480 | 600 | 720 | 960 | 'fullscreen';
17
+ /**
18
+ * Разрешить закрытие по Escape.
19
+ * @default true
20
+ */
21
+ escapeKeyDown?: boolean;
22
+ /**
23
+ * Разрешить закрытие по подложке.
24
+ * @default true
25
+ */
26
+ backdropClick?: boolean;
27
+ /**
28
+ * Блокировать прокрутку страницы.
29
+ * @default true
30
+ */
31
+ lockScroll?: boolean;
32
+ /**
33
+ * Контейнер портала. По умолчанию используется body текущего документа.
34
+ */
35
+ getPortalContainer?: () => Element | null;
36
+ /**
37
+ * Идентификатор для автоматизированных тестов.
38
+ * Части наследуют его с суффиксами -header, -content, -footer и -controls.
39
+ */
40
+ dataTestId?: string;
41
+ };
File without changes
@@ -0,0 +1 @@
1
+ export declare function lockScroll(document: Document): () => void;
@@ -0,0 +1,31 @@
1
+ const locks = new WeakMap();
2
+ function lockScroll(document) {
3
+ const { body, documentElement, defaultView } = document;
4
+ const existing = locks.get(document);
5
+ if (existing) existing.count += 1;
6
+ else {
7
+ locks.set(document, {
8
+ count: 1,
9
+ overflow: body.style.overflow,
10
+ paddingRight: body.style.paddingRight
11
+ });
12
+ const scrollbarWidth = (defaultView?.innerWidth ?? 0) - documentElement.clientWidth;
13
+ const hasStableGutter = defaultView?.getComputedStyle(documentElement).scrollbarGutter?.split(/\s+/).includes('stable');
14
+ if (scrollbarWidth > 0 && defaultView && !hasStableGutter) {
15
+ const paddingRight = parseFloat(defaultView.getComputedStyle(body).paddingRight) || 0;
16
+ body.style.paddingRight = `${paddingRight + scrollbarWidth}px`;
17
+ }
18
+ body.style.overflow = 'hidden';
19
+ }
20
+ return ()=>{
21
+ const lock = locks.get(document);
22
+ if (!lock) return;
23
+ lock.count -= 1;
24
+ if (0 === lock.count) {
25
+ body.style.overflow = lock.overflow;
26
+ body.style.paddingRight = lock.paddingRight;
27
+ locks.delete(document);
28
+ }
29
+ };
30
+ }
31
+ export { lockScroll };
@@ -0,0 +1,9 @@
1
+ :root {
2
+ --modal-background-color: #f5f3ec;
3
+ --modal-color: #1c1a18;
4
+ --modal-backdrop-color: #000000b3;
5
+ --modal-backdrop-blur: 2px;
6
+ --modal-shadow: 0 12px 32px -8px #0003;
7
+ --modal-padding: var(--size-24, 24px);
8
+ }
9
+
@@ -1,15 +1,17 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
- import { createPortal } from "react-dom";
3
+ import { Portal } from "../Portal/index.js";
4
4
  import { PopoverSurface } from "./components/popover-surface/index.js";
5
5
  const Popover = /*#__PURE__*/ forwardRef(({ open, anchorElement, getPortalContainer, ...restProps }, ref)=>{
6
6
  if (!open || !anchorElement) return null;
7
- const container = getPortalContainer ? getPortalContainer() : anchorElement.ownerDocument.body;
8
- return container ? /*#__PURE__*/ createPortal(/*#__PURE__*/ jsx(PopoverSurface, {
9
- ...restProps,
10
- anchorElement: anchorElement,
11
- ref: ref
12
- }), container) : null;
7
+ return /*#__PURE__*/ jsx(Portal, {
8
+ getPortalContainer: getPortalContainer ?? (()=>anchorElement.ownerDocument.body),
9
+ children: /*#__PURE__*/ jsx(PopoverSurface, {
10
+ ...restProps,
11
+ anchorElement: anchorElement,
12
+ ref: ref
13
+ })
14
+ });
13
15
  });
14
16
  Popover.displayName = 'Popover';
15
17
  export { Popover };
@@ -2,7 +2,9 @@ import type { Placement } from '@popperjs/core';
2
2
  import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';
3
3
  export type PopoverPosition = Exclude<Placement, 'auto' | 'auto-start' | 'auto-end'>;
4
4
  export type PopoverProps = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'className' | 'style'> & {
5
- /** Содержимое поповера. Оформление и прокрутка задаются вызывающим компонентом. */
5
+ /**
6
+ * Содержимое поповера. Оформление и прокрутка задаются вызывающим компонентом.
7
+ */
6
8
  children?: ReactNode;
7
9
  /**
8
10
  * Дополнительный класс внешнего контейнера.
@@ -0,0 +1,2 @@
1
+ export { Portal } from './portal.js';
2
+ export type { PortalProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { Portal } from "./portal.js";
@@ -0,0 +1,2 @@
1
+ import type { PortalProps } from './types.js';
2
+ export declare const Portal: import("react").ForwardRefExoticComponent<PortalProps & import("react").RefAttributes<Element | null>>;
@@ -0,0 +1,19 @@
1
+ import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
2
+ import { createPortal } from "react-dom";
3
+ function getBody() {
4
+ return "u" < typeof document ? null : document.body;
5
+ }
6
+ const Portal = /*#__PURE__*/ forwardRef(({ children, getPortalContainer = getBody, immediateMount = true }, ref)=>{
7
+ const [deferredContainer, setDeferredContainer] = useState(null);
8
+ let container = deferredContainer;
9
+ if (immediateMount) container = "u" < typeof document ? null : getPortalContainer() ?? null;
10
+ useEffect(()=>{
11
+ if (!immediateMount) setDeferredContainer(getPortalContainer() ?? null);
12
+ });
13
+ useImperativeHandle(ref, ()=>container, [
14
+ container
15
+ ]);
16
+ return container ? /*#__PURE__*/ createPortal(children, container) : null;
17
+ });
18
+ Portal.displayName = 'Portal';
19
+ export { Portal };
@@ -0,0 +1,18 @@
1
+ import type { ReactNode } from 'react';
2
+ export type PortalProps = {
3
+ /**
4
+ * Содержимое, которое будет перенесено в контейнер портала без дополнительной обёртки.
5
+ */
6
+ children?: ReactNode;
7
+ /**
8
+ * Контейнер портала. По умолчанию используется body текущего документа.
9
+ * Если функция возвращает null или undefined, содержимое не рендерится.
10
+ */
11
+ getPortalContainer?: () => Element | null | undefined;
12
+ /**
13
+ * Рендерить содержимое сразу, если контейнер уже существует.
14
+ * При false контейнер определяется после монтирования, чтобы дождаться DOM-контейнера из ref.
15
+ * @default true
16
+ */
17
+ immediateMount?: boolean;
18
+ };
File without changes
@@ -2,11 +2,17 @@ import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';
2
2
  export type TypographyWeight = 'regular' | 'medium' | 'semibold' | 'bold';
3
3
  export type TypographyColor = 'inherit' | 'primary' | 'secondary' | 'inverse' | 'positive' | 'negative';
4
4
  export type BaseProps = Omit<HTMLAttributes<HTMLElement>, 'color' | 'children' | 'className' | 'style'> & {
5
- /** Содержимое текста или заголовка. */
5
+ /**
6
+ * Содержимое текста или заголовка.
7
+ */
6
8
  children?: ReactNode;
7
- /** Дополнительный CSS-класс корневого элемента. */
9
+ /**
10
+ * Дополнительный CSS-класс корневого элемента.
11
+ */
8
12
  className?: string;
9
- /** Инлайн-стили корневого элемента. */
13
+ /**
14
+ * Инлайн-стили корневого элемента.
15
+ */
10
16
  style?: CSSProperties;
11
17
  /**
12
18
  * Цвет текста. По умолчанию наследуется от родителя.
package/dist/index.d.ts CHANGED
@@ -6,3 +6,9 @@ export { Typography, TypographyText, TypographyTitle, Text, Title } from './comp
6
6
  export type { TextProps, TitleProps, TypographyColor, TypographyWeight, } from './components/Typography/index.js';
7
7
  export { Popover } from './components/Popover/index.js';
8
8
  export type { PopoverProps, PopoverPosition } from './components/Popover/index.js';
9
+ export { Collapse } from './components/Collapse/index.js';
10
+ export type { CollapseProps } from './components/Collapse/index.js';
11
+ export { Modal, ModalComponent, ModalHeader, ModalContent, ModalFooter, ModalControls, } from './components/Modal/index.js';
12
+ export { Portal } from './components/Portal/index.js';
13
+ export type { PortalProps } from './components/Portal/index.js';
14
+ export type { ModalProps, HeaderProps as ModalHeaderProps, ContentProps as ModalContentProps, FooterProps as ModalFooterProps, ControlsProps as ModalControlsProps, } from './components/Modal/index.js';
package/dist/index.js CHANGED
@@ -2,3 +2,6 @@ export { Button } from "./components/Button/index.js";
2
2
  export { Spinner } from "./components/Spinner/index.js";
3
3
  export { Text, Title, Typography, TypographyText, TypographyTitle } from "./components/Typography/index.js";
4
4
  export { Popover } from "./components/Popover/index.js";
5
+ export { Collapse } from "./components/Collapse/index.js";
6
+ export { Modal, ModalComponent, ModalContent, ModalControls, ModalFooter, ModalHeader } from "./components/Modal/index.js";
7
+ export { Portal } from "./components/Portal/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koslibs/components",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Shared React components for koslibs projects",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -80,6 +80,7 @@
80
80
  "react-dom": "^18.3.1 || ^19.0.0"
81
81
  },
82
82
  "dependencies": {
83
+ "@koslibs/icons": "1.0.1",
83
84
  "@popperjs/core": "2.11.8",
84
85
  "classnames": "2.5.1"
85
86
  }