@shmidko61/lc-ui-kit 0.17.0 → 0.18.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 +39 -16
- package/dist/dropdown-menu/dropdown-menu.d.ts +4 -0
- package/dist/dropdown-menu/helpers/dropdown-menu.helpers.d.ts +4 -0
- package/dist/dropdown-menu/helpers/index.d.ts +1 -0
- package/dist/dropdown-menu/index.d.ts +2 -0
- package/dist/dropdown-menu/types/dropdown-menu.types.d.ts +66 -0
- package/dist/dropdown-menu/types/index.d.ts +1 -0
- package/dist/dropdown-menu/types/internal/dropdown-menu-internal.types.d.ts +17 -0
- package/dist/dropdown-menu/types/internal/index.d.ts +1 -0
- package/dist/dropdown-menu-D14xkawH.js +199 -0
- package/dist/dropdown-menu-hivkBAku.cjs +1 -0
- package/dist/dropdown-menu.cjs +1 -0
- package/dist/dropdown-menu.js +5 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +95 -93
- package/dist/styles.css +1 -1
- package/package.json +43 -31
package/README.md
CHANGED
|
@@ -7,24 +7,41 @@
|
|
|
7
7
|
Из каталога `apps`:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
corepack pnpm
|
|
10
|
+
corepack pnpm release:check:ui-kit
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Команда
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
Команда устанавливает зависимости по frozen lockfile, удаляет старый `dist`,
|
|
14
|
+
запускает lint, typecheck, тесты, сборку и Storybook. Затем `npm pack` создаёт
|
|
15
|
+
реальный tarball в `.release/ui-kit`; пакет устанавливается в отдельный временный
|
|
16
|
+
consumer без workspace-ссылок. Зависимости consumer фиксирует собственный
|
|
17
|
+
`package-lock.json`.
|
|
18
|
+
|
|
19
|
+
Проверяются все exports (ESM/CJS/types), декларации, файлы stylesheet, safelist,
|
|
20
|
+
каждый CSS-файл через Lightning CSS с минификацией и запрет `${…}` в декларациях
|
|
21
|
+
CSS. Consumer компилирует `contentInnerProps`, padding заголовка, md/lg/xl и
|
|
22
|
+
собирается на Vite 7.3.6 и 8.3.5 с `cssMinify: 'lightningcss'`. Chromium проверяет
|
|
23
|
+
реальный padding, нулевые значения, responsive/reset/style, клавиатуру, ARIA,
|
|
24
|
+
динамическую высоту и анимации на всех breakpoint. Негативные регрессии проверяют
|
|
25
|
+
невалидный CSS и исчезновение публичного prop.
|
|
26
|
+
|
|
27
|
+
Для браузерных проверок Chromium устанавливается автоматически. Можно задать
|
|
28
|
+
`CHROME_BIN` на существующий Chrome. На Linux нужны системные зависимости
|
|
29
|
+
Playwright/Chromium (в CI используется Chrome из ubuntu-latest).
|
|
30
|
+
При ошибке лог содержит этап `[release:…]` и путь consumer для диагностики.
|
|
31
|
+
|
|
32
|
+
`corepack pnpm publish:ui-kit` проверяет npm-пользователя, выполняет весь pipeline
|
|
33
|
+
и публикует **тот же tarball**, сверяя SHA-256 с `verified.json`. Повторной сборки
|
|
34
|
+
между проверкой и публикацией нет. Ввода PUBLISH нет; npm может запросить 2FA.
|
|
35
|
+
Прямая публикация из каталога пакета блокируется `prepublishOnly`.
|
|
36
|
+
|
|
37
|
+
CI workflow **UI-kit artifact gate** выполняет обязательный verify job;
|
|
38
|
+
публикация при ручном запуске с `publish=true` зависит от него и скачивает
|
|
39
|
+
проверенный tarball. Для npm нужен секрет `NPM_TOKEN`. Чтобы запретить merge при
|
|
40
|
+
ошибке, назначьте job `verify` обязательным в branch protection репозитория.
|
|
41
|
+
Никакие проверки не используют `allow_failure`/`continue-on-error`.
|
|
42
|
+
|
|
43
|
+
`verify:package` остаётся быстрым набором локальных проверок исходников и dist;
|
|
44
|
+
он не заменяет обязательную проверку релизного tarball.
|
|
28
45
|
|
|
29
46
|
## Установка
|
|
30
47
|
|
|
@@ -249,3 +266,9 @@ export function Question() {
|
|
|
249
266
|
```
|
|
250
267
|
|
|
251
268
|
Storybook: **UI Kit / Accordion / ContentInner**.
|
|
269
|
+
|
|
270
|
+
## DropdownMenu
|
|
271
|
+
|
|
272
|
+
Меню действий с клавиатурой, поиском, portal, автоматическим позиционированием,
|
|
273
|
+
прокруткой, controlled/uncontrolled состоянием и настройкой обёрток через BoxProps.
|
|
274
|
+
Импорт: `@shmidko61/lc-ui-kit/dropdown-menu`. [API и примеры](src/dropdown-menu/README.md).
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Находит соседний tab-stop относительно триггера, исключая закрываемую portal-панель.
|
|
2
|
+
* Положительные tabindex идут первыми, скрытые и disabled-элементы пропускаются.
|
|
3
|
+
*/
|
|
4
|
+
export declare function getDropdownTabTarget(trigger: HTMLButtonElement, panel: HTMLElement | null, backwards: boolean): HTMLElement | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getDropdownTabTarget } from './dropdown-menu.helpers';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { BoxProps } from '../../box/index';
|
|
3
|
+
/** Настройки обёртки без замены семантического элемента и содержимого. style имеет итоговый приоритет. */
|
|
4
|
+
export type DropdownMenuBoxProps = Omit<BoxProps, 'as' | 'children'>;
|
|
5
|
+
/** Пункт меню действий; id уникален, textValue используется для поиска с клавиатуры. */
|
|
6
|
+
export interface DropdownMenuItem {
|
|
7
|
+
/** Уникальный ключ действия. */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Видимая подпись или произвольное содержимое. */
|
|
10
|
+
label: ReactNode;
|
|
11
|
+
/** Текст для поиска; обязателен для сложной JSX-подписи. */
|
|
12
|
+
textValue?: string;
|
|
13
|
+
/** Дополнительное описание действия. */
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
/** Начальный слот: например, иконка. */
|
|
16
|
+
leading?: ReactNode;
|
|
17
|
+
/** Конечный слот: например, сочетание клавиш. */
|
|
18
|
+
trailing?: ReactNode;
|
|
19
|
+
/** Недоступный пункт пропускается при навигации. */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Деструктивное действие окрашивается в красный. */
|
|
22
|
+
destructive?: boolean;
|
|
23
|
+
/** Индивидуальное оформление пункта, включая md/lg/xl; style приоритетнее. */
|
|
24
|
+
boxProps?: DropdownMenuBoxProps;
|
|
25
|
+
}
|
|
26
|
+
/** Props меню действий. Для выбора значения формы используйте Select. */
|
|
27
|
+
export interface DropdownMenuProps {
|
|
28
|
+
/** Список действий; пустой список отображает emptyContent. */
|
|
29
|
+
items: Array<DropdownMenuItem>;
|
|
30
|
+
/** Содержимое стандартной кнопки. По умолчанию «Действия». */
|
|
31
|
+
trigger?: ReactNode;
|
|
32
|
+
/** Настройка кнопки через Box, включая md/lg/xl, className, style и HTML props. */
|
|
33
|
+
triggerProps?: Omit<BoxProps<'button'>, 'as' | 'children'>;
|
|
34
|
+
/** Внешняя обёртка триггера. */
|
|
35
|
+
rootProps?: DropdownMenuBoxProps;
|
|
36
|
+
/** Оформление позиционируемой панели. */
|
|
37
|
+
panelProps?: DropdownMenuBoxProps;
|
|
38
|
+
/** Оформление списка: padding, maxHeight, scrollbar и md/lg/xl. */
|
|
39
|
+
menuProps?: DropdownMenuBoxProps;
|
|
40
|
+
/** Общие настройки пунктов; индивидуальные boxProps имеют приоритет. */
|
|
41
|
+
itemProps?: DropdownMenuBoxProps;
|
|
42
|
+
/** Кастомизация содержимого пункта без изменения его доступной семантики. */
|
|
43
|
+
renderItem?: (item: DropdownMenuItem) => ReactNode;
|
|
44
|
+
/** Доступное название списка; по умолчанию «Действия». */
|
|
45
|
+
label?: string;
|
|
46
|
+
/** Содержимое при отсутствии действий. По умолчанию «Нет действий». */
|
|
47
|
+
emptyContent?: ReactNode;
|
|
48
|
+
/** Controlled-состояние панели. */
|
|
49
|
+
open?: boolean;
|
|
50
|
+
/** Начальное раскрытие uncontrolled-панели; по умолчанию false. */
|
|
51
|
+
defaultOpen?: boolean;
|
|
52
|
+
/** Изменение раскрытия. */
|
|
53
|
+
onOpenChange?: (open: boolean) => void;
|
|
54
|
+
/** Выбор доступного действия. */
|
|
55
|
+
onAction?: (id: string) => void;
|
|
56
|
+
/** Отключает триггер; по умолчанию false. */
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
/** Закрывать после действия; по умолчанию true. */
|
|
59
|
+
closeOnSelect?: boolean;
|
|
60
|
+
/** Положение с автоматическим переворотом у края экрана; по умолчанию bottom start. */
|
|
61
|
+
placement?: DropdownMenuPlacement;
|
|
62
|
+
/** Расстояние от триггера в px; по умолчанию 8. */
|
|
63
|
+
offset?: number;
|
|
64
|
+
}
|
|
65
|
+
/** Положение панели: физические left/right либо логические start/end с учётом направления текста. */
|
|
66
|
+
export type DropdownMenuPlacement = 'top' | 'bottom' | 'left' | 'right' | 'start' | 'end' | `${'top' | 'bottom'} ${'left' | 'right' | 'start' | 'end'}` | `${'left' | 'right' | 'start' | 'end'} ${'top' | 'bottom'}`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { DropdownMenuBoxProps, DropdownMenuItem, DropdownMenuPlacement, DropdownMenuProps, } from './dropdown-menu.types';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { TreeState, useMenuTriggerState } from 'react-stately';
|
|
3
|
+
import { DropdownMenuItem, DropdownMenuProps } from '..';
|
|
4
|
+
/** Внутренние props доступного пункта. */
|
|
5
|
+
export interface DropdownMenuEntryProps {
|
|
6
|
+
item: DropdownMenuItem;
|
|
7
|
+
state: TreeState<DropdownMenuItem>;
|
|
8
|
+
options: DropdownMenuProps;
|
|
9
|
+
close: () => void;
|
|
10
|
+
}
|
|
11
|
+
/** Внутренние props позиционируемой панели. */
|
|
12
|
+
export interface DropdownMenuPanelProps {
|
|
13
|
+
options: DropdownMenuProps;
|
|
14
|
+
triggerRef: RefObject<HTMLButtonElement | null>;
|
|
15
|
+
state: ReturnType<typeof useMenuTriggerState>;
|
|
16
|
+
triggerMenuProps: object;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { DropdownMenuEntryProps, DropdownMenuPanelProps, } from './dropdown-menu-internal.types';
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as b, jsx as l } from "react/jsx-runtime";
|
|
3
|
+
import { useRef as g, useId as P, useEffect as I, useLayoutEffect as O } from "react";
|
|
4
|
+
import { useMenuTrigger as w, useButton as D, mergeProps as m, usePopover as S, useMenu as v, Overlay as k, FocusScope as T, DismissButton as x, useMenuItem as C } from "react-aria";
|
|
5
|
+
import { useMenuTriggerState as M, useTreeState as F, Item as A } from "react-stately";
|
|
6
|
+
import { Box as a } from "./box.js";
|
|
7
|
+
import { Flex as E } from "./flex.js";
|
|
8
|
+
import { Typography as R } from "./typography.js";
|
|
9
|
+
function V(e, i, t) {
|
|
10
|
+
const o = Array.from(
|
|
11
|
+
e.ownerDocument.querySelectorAll(
|
|
12
|
+
'a[href],button,input,select,textarea,[tabindex],[contenteditable="true"]'
|
|
13
|
+
)
|
|
14
|
+
).filter(
|
|
15
|
+
(r) => r.tabIndex >= 0 && !r.matches(":disabled") && !r.closest("[inert]") && r.getClientRects().length > 0 && !0
|
|
16
|
+
).sort(
|
|
17
|
+
(r, s) => (r.tabIndex > 0 ? r.tabIndex : 1 / 0) - (s.tabIndex > 0 ? s.tabIndex : 1 / 0)
|
|
18
|
+
);
|
|
19
|
+
return o[o.indexOf(e) + (t ? -1 : 1)];
|
|
20
|
+
}
|
|
21
|
+
function q({ item: e, state: i, options: t, close: o }) {
|
|
22
|
+
const r = g(null), { menuItemProps: s, labelProps: c, descriptionProps: f, isFocused: u } = C(
|
|
23
|
+
{
|
|
24
|
+
key: e.id,
|
|
25
|
+
onAction: () => t.onAction?.(e.id),
|
|
26
|
+
onClose: o,
|
|
27
|
+
closeOnSelect: t.closeOnSelect ?? !0
|
|
28
|
+
},
|
|
29
|
+
i,
|
|
30
|
+
r
|
|
31
|
+
);
|
|
32
|
+
return /* @__PURE__ */ l(
|
|
33
|
+
a,
|
|
34
|
+
{
|
|
35
|
+
outlineStyle: "none",
|
|
36
|
+
focusVisible: {
|
|
37
|
+
outlineStyle: "solid",
|
|
38
|
+
outlineWidth: "2px",
|
|
39
|
+
outlineOffset: "-2px",
|
|
40
|
+
outlineColor: "--color-primary-accent"
|
|
41
|
+
},
|
|
42
|
+
p: { px: 16, py: 12 },
|
|
43
|
+
border: { radius: "8px" },
|
|
44
|
+
color: e.destructive ? "#dc2626" : "--color-text-primary",
|
|
45
|
+
bg: u ? "--color-background-subtle" : void 0,
|
|
46
|
+
...m(t.itemProps ?? {}, e.boxProps ?? {}, s),
|
|
47
|
+
ref: r,
|
|
48
|
+
style: { ...t.itemProps?.style, ...e.boxProps?.style },
|
|
49
|
+
children: t.renderItem ? /* @__PURE__ */ l(a, { ...c, children: t.renderItem(e) }) : /* @__PURE__ */ b(E, { align: "center", gap: 12, children: [
|
|
50
|
+
e.leading,
|
|
51
|
+
/* @__PURE__ */ b(a, { width: "100%", children: [
|
|
52
|
+
/* @__PURE__ */ l(a, { ...c, children: e.label }),
|
|
53
|
+
e.description && /* @__PURE__ */ l(R, { ...f, variant: "b3", color: "--color-text-secondary", children: e.description })
|
|
54
|
+
] }),
|
|
55
|
+
e.trailing
|
|
56
|
+
] })
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function B({
|
|
61
|
+
options: e,
|
|
62
|
+
triggerRef: i,
|
|
63
|
+
state: t,
|
|
64
|
+
triggerMenuProps: o
|
|
65
|
+
}) {
|
|
66
|
+
const r = g(null), s = g(null), { popoverProps: c, underlayProps: f } = S(
|
|
67
|
+
{
|
|
68
|
+
popoverRef: r,
|
|
69
|
+
triggerRef: i,
|
|
70
|
+
placement: e.placement ?? "bottom start",
|
|
71
|
+
offset: e.offset ?? 8
|
|
72
|
+
},
|
|
73
|
+
t
|
|
74
|
+
), u = F({
|
|
75
|
+
items: e.items,
|
|
76
|
+
disabledKeys: e.items.filter((n) => n.disabled).map((n) => n.id),
|
|
77
|
+
selectionMode: "none",
|
|
78
|
+
children: (n) => /* @__PURE__ */ l(
|
|
79
|
+
A,
|
|
80
|
+
{
|
|
81
|
+
textValue: n.textValue ?? (typeof n.label == "string" ? n.label : n.id),
|
|
82
|
+
children: n.label
|
|
83
|
+
},
|
|
84
|
+
n.id
|
|
85
|
+
)
|
|
86
|
+
}), { menuProps: d } = v(
|
|
87
|
+
{
|
|
88
|
+
...o,
|
|
89
|
+
...e.label ? { "aria-labelledby": void 0 } : {},
|
|
90
|
+
onClose: t.close,
|
|
91
|
+
"aria-label": e.label ?? "Действия",
|
|
92
|
+
autoFocus: t.focusStrategy ?? "first"
|
|
93
|
+
},
|
|
94
|
+
u,
|
|
95
|
+
s
|
|
96
|
+
);
|
|
97
|
+
return /* @__PURE__ */ b(k, { children: [
|
|
98
|
+
/* @__PURE__ */ l(a, { ...f, position: { type: "fixed", top: 0, right: 0, bottom: 0, left: 0 } }),
|
|
99
|
+
/* @__PURE__ */ l(T, { restoreFocus: !0, children: /* @__PURE__ */ b(
|
|
100
|
+
a,
|
|
101
|
+
{
|
|
102
|
+
bg: "--color-background-default",
|
|
103
|
+
border: { radius: "12px" },
|
|
104
|
+
boxShadow: "0 8px 32px rgba(0,0,0,.12)",
|
|
105
|
+
...m(e.panelProps ?? {}, c),
|
|
106
|
+
ref: r,
|
|
107
|
+
style: { ...c.style, ...e.panelProps?.style },
|
|
108
|
+
children: [
|
|
109
|
+
/* @__PURE__ */ l(x, { onDismiss: t.close }),
|
|
110
|
+
/* @__PURE__ */ l(
|
|
111
|
+
a,
|
|
112
|
+
{
|
|
113
|
+
outlineStyle: "none",
|
|
114
|
+
p: 8,
|
|
115
|
+
minWidth: 220,
|
|
116
|
+
maxHeight: "min(320px, 60vh)",
|
|
117
|
+
overflowY: "auto",
|
|
118
|
+
...m(e.menuProps ?? {}, d),
|
|
119
|
+
ref: s,
|
|
120
|
+
children: e.items.length ? e.items.map((n) => /* @__PURE__ */ l(
|
|
121
|
+
q,
|
|
122
|
+
{
|
|
123
|
+
item: n,
|
|
124
|
+
state: u,
|
|
125
|
+
options: e,
|
|
126
|
+
close: t.close
|
|
127
|
+
},
|
|
128
|
+
n.id
|
|
129
|
+
)) : /* @__PURE__ */ l(a, { p: 16, children: e.emptyContent ?? "Нет действий" })
|
|
130
|
+
}
|
|
131
|
+
),
|
|
132
|
+
/* @__PURE__ */ l(x, { onDismiss: t.close })
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
) })
|
|
136
|
+
] });
|
|
137
|
+
}
|
|
138
|
+
function J(e) {
|
|
139
|
+
const i = g(null), t = P(), o = e.disabled ?? e.triggerProps?.disabled ?? !1, r = M({
|
|
140
|
+
isOpen: e.open,
|
|
141
|
+
defaultOpen: o ? !1 : e.defaultOpen,
|
|
142
|
+
onOpenChange: e.onOpenChange
|
|
143
|
+
}), s = g(!1);
|
|
144
|
+
I(() => {
|
|
145
|
+
!o || !r.isOpen ? s.current = !1 : s.current || (s.current = !0, r.close());
|
|
146
|
+
}, [o, r]);
|
|
147
|
+
const { menuTriggerProps: c, menuProps: f } = w(
|
|
148
|
+
{ type: "menu", isDisabled: o },
|
|
149
|
+
r,
|
|
150
|
+
i
|
|
151
|
+
), { buttonProps: u } = D(
|
|
152
|
+
{ ...m(c, e.triggerProps ?? {}), isDisabled: o },
|
|
153
|
+
i
|
|
154
|
+
);
|
|
155
|
+
return O(() => {
|
|
156
|
+
const d = i.current;
|
|
157
|
+
if (!d || !r.isOpen) return;
|
|
158
|
+
const n = d.ownerDocument, y = (p) => {
|
|
159
|
+
if (p.key !== "Tab" || !(p.target instanceof Element) || p.target.closest('[role="menu"]')?.id !== t)
|
|
160
|
+
return;
|
|
161
|
+
p.preventDefault(), p.stopPropagation();
|
|
162
|
+
const h = p.shiftKey;
|
|
163
|
+
r.close(), requestAnimationFrame(
|
|
164
|
+
() => requestAnimationFrame(() => {
|
|
165
|
+
(V(d, null, h) ?? d).focus();
|
|
166
|
+
})
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
return n.defaultView?.addEventListener("keydown", y, !0), () => n.defaultView?.removeEventListener("keydown", y, !0);
|
|
170
|
+
}, [r, t]), /* @__PURE__ */ b(a, { display: "inline-block", ...e.rootProps, children: [
|
|
171
|
+
/* @__PURE__ */ l(
|
|
172
|
+
a,
|
|
173
|
+
{
|
|
174
|
+
as: "button",
|
|
175
|
+
p: { px: 16, py: 10 },
|
|
176
|
+
bg: "--color-background-subtle",
|
|
177
|
+
border: { radius: "8px", style: "none" },
|
|
178
|
+
...e.triggerProps,
|
|
179
|
+
...u,
|
|
180
|
+
"aria-expanded": !o && r.isOpen,
|
|
181
|
+
"aria-controls": r.isOpen && !o ? t : void 0,
|
|
182
|
+
ref: i,
|
|
183
|
+
children: e.trigger ?? "Действия"
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
r.isOpen && !o && /* @__PURE__ */ l(
|
|
187
|
+
B,
|
|
188
|
+
{
|
|
189
|
+
options: e,
|
|
190
|
+
state: r,
|
|
191
|
+
triggerRef: i,
|
|
192
|
+
triggerMenuProps: { ...f, id: t }
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] });
|
|
196
|
+
}
|
|
197
|
+
export {
|
|
198
|
+
J as D
|
|
199
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";"use strict";const s=require("react/jsx-runtime"),a=require("react"),l=require("react-aria"),g=require("react-stately"),c=require("./box.cjs"),h=require("./flex.cjs"),P=require("./typography.cjs");function j(e,i,t){const o=Array.from(e.ownerDocument.querySelectorAll('a[href],button,input,select,textarea,[tabindex],[contenteditable="true"]')).filter(r=>r.tabIndex>=0&&!r.matches(":disabled")&&!r.closest("[inert]")&&r.getClientRects().length>0&&!0).sort((r,u)=>(r.tabIndex>0?r.tabIndex:1/0)-(u.tabIndex>0?u.tabIndex:1/0));return o[o.indexOf(e)+(t?-1:1)]}function I({item:e,state:i,options:t,close:o}){const r=a.useRef(null),{menuItemProps:u,labelProps:d,descriptionProps:b,isFocused:p}=l.useMenuItem({key:e.id,onAction:()=>t.onAction?.(e.id),onClose:o,closeOnSelect:t.closeOnSelect??!0},i,r);return s.jsx(c.Box,{outlineStyle:"none",focusVisible:{outlineStyle:"solid",outlineWidth:"2px",outlineOffset:"-2px",outlineColor:"--color-primary-accent"},p:{px:16,py:12},border:{radius:"8px"},color:e.destructive?"#dc2626":"--color-text-primary",bg:p?"--color-background-subtle":void 0,...l.mergeProps(t.itemProps??{},e.boxProps??{},u),ref:r,style:{...t.itemProps?.style,...e.boxProps?.style},children:t.renderItem?s.jsx(c.Box,{...d,children:t.renderItem(e)}):s.jsxs(h.Flex,{align:"center",gap:12,children:[e.leading,s.jsxs(c.Box,{width:"100%",children:[s.jsx(c.Box,{...d,children:e.label}),e.description&&s.jsx(P.Typography,{...b,variant:"b3",color:"--color-text-secondary",children:e.description})]}),e.trailing]})})}function O({options:e,triggerRef:i,state:t,triggerMenuProps:o}){const r=a.useRef(null),u=a.useRef(null),{popoverProps:d,underlayProps:b}=l.usePopover({popoverRef:r,triggerRef:i,placement:e.placement??"bottom start",offset:e.offset??8},t),p=g.useTreeState({items:e.items,disabledKeys:e.items.filter(n=>n.disabled).map(n=>n.id),selectionMode:"none",children:n=>s.jsx(g.Item,{textValue:n.textValue??(typeof n.label=="string"?n.label:n.id),children:n.label},n.id)}),{menuProps:x}=l.useMenu({...o,...e.label?{"aria-labelledby":void 0}:{},onClose:t.close,"aria-label":e.label??"Действия",autoFocus:t.focusStrategy??"first"},p,u);return s.jsxs(l.Overlay,{children:[s.jsx(c.Box,{...b,position:{type:"fixed",top:0,right:0,bottom:0,left:0}}),s.jsx(l.FocusScope,{restoreFocus:!0,children:s.jsxs(c.Box,{bg:"--color-background-default",border:{radius:"12px"},boxShadow:"0 8px 32px rgba(0,0,0,.12)",...l.mergeProps(e.panelProps??{},d),ref:r,style:{...d.style,...e.panelProps?.style},children:[s.jsx(l.DismissButton,{onDismiss:t.close}),s.jsx(c.Box,{outlineStyle:"none",p:8,minWidth:220,maxHeight:"min(320px, 60vh)",overflowY:"auto",...l.mergeProps(e.menuProps??{},x),ref:u,children:e.items.length?e.items.map(n=>s.jsx(I,{item:n,state:p,options:e,close:t.close},n.id)):s.jsx(c.Box,{p:16,children:e.emptyContent??"Нет действий"})}),s.jsx(l.DismissButton,{onDismiss:t.close})]})})]})}function w(e){const i=a.useRef(null),t=a.useId(),o=e.disabled??e.triggerProps?.disabled??!1,r=g.useMenuTriggerState({isOpen:e.open,defaultOpen:o?!1:e.defaultOpen,onOpenChange:e.onOpenChange}),u=a.useRef(!1);a.useEffect(()=>{!o||!r.isOpen?u.current=!1:u.current||(u.current=!0,r.close())},[o,r]);const{menuTriggerProps:d,menuProps:b}=l.useMenuTrigger({type:"menu",isDisabled:o},r,i),{buttonProps:p}=l.useButton({...l.mergeProps(d,e.triggerProps??{}),isDisabled:o},i);return a.useLayoutEffect(()=>{const x=i.current;if(!x||!r.isOpen)return;const n=x.ownerDocument,y=f=>{if(f.key!=="Tab"||!(f.target instanceof Element)||f.target.closest('[role="menu"]')?.id!==t)return;f.preventDefault(),f.stopPropagation();const m=f.shiftKey;r.close(),requestAnimationFrame(()=>requestAnimationFrame(()=>{(j(x,null,m)??x).focus()}))};return n.defaultView?.addEventListener("keydown",y,!0),()=>n.defaultView?.removeEventListener("keydown",y,!0)},[r,t]),s.jsxs(c.Box,{display:"inline-block",...e.rootProps,children:[s.jsx(c.Box,{as:"button",p:{px:16,py:10},bg:"--color-background-subtle",border:{radius:"8px",style:"none"},...e.triggerProps,...p,"aria-expanded":!o&&r.isOpen,"aria-controls":r.isOpen&&!o?t:void 0,ref:i,children:e.trigger??"Действия"}),r.isOpen&&!o&&s.jsx(O,{options:e,state:r,triggerRef:i,triggerMenuProps:{...b,id:t}})]})}exports.DropdownMenu=w;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./dropdown-menu-hivkBAku.cjs");exports.DropdownMenu=e.DropdownMenu;
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./accordion.cjs"),l=require("./alert-DTc0Usg-.cjs"),I=require("./box.cjs"),n=require("./button.cjs"),r=require("./ui-kit-provider-raEFsUm0.cjs"),u=require("./flex.cjs"),a=require("./grid.cjs"),o=require("./icons.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./accordion.cjs"),l=require("./alert-DTc0Usg-.cjs"),I=require("./box.cjs"),n=require("./button.cjs"),r=require("./ui-kit-provider-raEFsUm0.cjs"),u=require("./dropdown-menu-hivkBAku.cjs"),d=require("./flex.cjs"),a=require("./grid.cjs"),o=require("./icons.cjs"),p=require("./input.cjs"),T=require("./loader-ODTCTLKE.cjs"),b=require("./media-card.cjs"),g=require("./media-gallery.cjs"),t=require("./notification-provider-C2ypXy2W.cjs"),C=require("./pagination.cjs"),k=require("./picture.cjs"),M=require("./progress-bar-XIJDb_UM.cjs"),S=require("./select.cjs"),c=require("./responsive-style.config-B2m9jVlX.cjs"),h=require("./status-badge.cjs"),q=require("./switch.cjs"),e=require("./table-container-DqqqkChm.cjs"),y=require("./tabs-BNZDJRz_.cjs"),P=require("./toast-CH8VqvLC.cjs"),B=require("./tooltip-0RbTCYn_.cjs"),s=require("./typography.cjs");exports.Accordion=i.Accordion;exports.AccordionItem=i.AccordionItem;exports.AccordionRoot=i.AccordionRoot;exports.Alert=l.Alert;exports.Box=I.Box;exports.Button=n.Button;exports.buttonSizeBorderRadius=n.buttonSizeBorderRadius;exports.buttonSizeBoxProps=n.buttonSizeBoxProps;exports.buttonSizeClassNames=n.buttonSizeClassNames;exports.buttonVariantClassNames=n.buttonVariantClassNames;exports.buttonVariants=n.buttonVariants;exports.UiKitProvider=r.UiKitProvider;exports.uiKitColorTokens=r.uiKitColorTokens;exports.uiKitTypographyTokens=r.uiKitTypographyTokens;exports.useUiKitConfig=r.useUiKitConfig;exports.DropdownMenu=u.DropdownMenu;exports.Flex=d.Flex;exports.Grid=a.Grid;exports.GridItem=a.GridItem;exports.ArrowCornerIcon=o.ArrowCornerIcon;exports.ArrowIcon=o.ArrowIcon;exports.ArrowLongLeftIcon=o.ArrowLongLeftIcon;exports.ArrowheadRightIcon=o.ArrowheadRightIcon;exports.BlockIcon=o.BlockIcon;exports.BurgerIcon=o.BurgerIcon;exports.CheckIcon=o.CheckIcon;exports.CopyIcon=o.CopyIcon;exports.DoubleCheckIcon=o.DoubleCheckIcon;exports.DropDown=o.DropDown;exports.ExclamationMarkIcon=o.ExclamationMarkIcon;exports.EyeOpenIcon=o.EyeOpenIcon;exports.FileIcon=o.FileIcon;exports.GeminiStarIcon=o.GeminiStarIcon;exports.GeoIcon=o.GeoIcon;exports.InfoCircleIcon=o.InfoCircleIcon;exports.LockClosedIcon=o.LockClosedIcon;exports.LockOpenIcon=o.LockOpenIcon;exports.LogoutIcon=o.LogoutIcon;exports.MailIcon=o.MailIcon;exports.MediaMaxIcon=o.MediaMaxIcon;exports.MediaPictureIcon=o.MediaPictureIcon;exports.MediaTgIcon=o.MediaTgIcon;exports.MediaVkIcon=o.MediaVkIcon;exports.MediaWaIcon=o.MediaWaIcon;exports.NetUploadIcon=o.NetUploadIcon;exports.PaperclipIcon=o.PaperclipIcon;exports.PdfIcon=o.PdfIcon;exports.PhoneIcon=o.PhoneIcon;exports.PlusIcon=o.PlusIcon;exports.SaveIcon=o.SaveIcon;exports.SparkIcon=o.SparkIcon;exports.SparkleIcon=o.SparkleIcon;exports.TelephoneIcon=o.TelephoneIcon;exports.TimeClockIcon=o.TimeClockIcon;exports.TrashIcon=o.TrashIcon;exports.WarningTriangleIcon=o.WarningTriangleIcon;exports.XMarkIcon=o.XMarkIcon;exports.Input=p.Input;exports.Loader=T.Loader;exports.MediaCard=b.MediaCard;exports.MediaGallery=g.MediaGallery;exports.NotificationProvider=t.NotificationProvider;exports.useNotifications=t.useNotifications;exports.Pagination=C.Pagination;exports.Picture=k.Picture;exports.ProgressBar=M.ProgressBar;exports.Select=S.Select;exports.responsiveBreakpointMinWidth=c.responsiveBreakpointMinWidth;exports.responsiveBreakpoints=c.responsiveBreakpoints;exports.StatusBadge=h.StatusBadge;exports.Switch=q.Switch;exports.DataTable=e.DataTable;exports.Table=e.Table;exports.TableBody=e.TableBody;exports.TableCaption=e.TableCaption;exports.TableCell=e.TableCell;exports.TableContainer=e.TableContainer;exports.TableFooter=e.TableFooter;exports.TableHead=e.TableHead;exports.TableHeader=e.TableHeader;exports.TableRow=e.TableRow;exports.TableScrollArea=e.TableScrollArea;exports.TableStatus=e.TableStatus;exports.TableToolbar=e.TableToolbar;exports.Tabs=y.Tabs;exports.Toast=P.Toast;exports.Tooltip=B.Tooltip;exports.Typography=s.Typography;exports.typographyVariants=s.typographyVariants;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { Box } from './box/box';
|
|
|
5
5
|
export * from './button/button';
|
|
6
6
|
export * from './design-tokens/color.tokens';
|
|
7
7
|
export * from './design-tokens/typography.tokens';
|
|
8
|
+
export * from './dropdown-menu/index';
|
|
8
9
|
export type { FlexBreakpointProps, FlexProps, FlexResponsiveProps } from './flex/flex';
|
|
9
10
|
export { Flex } from './flex/flex';
|
|
10
11
|
export * from './grid/grid';
|