@cystackapp/ui 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +77 -47
- package/dist/assets/background-pattern-grid.svg.js +7 -0
- package/dist/assets/empty-cloud.svg.js +5 -0
- package/dist/components/accordion/Accordion.d.ts +20 -0
- package/dist/components/accordion/Accordion.js +36 -0
- package/dist/components/accordion/AccordionTestStory.d.ts +3 -0
- package/dist/components/alert/Alert.d.ts +15 -0
- package/dist/components/alert/Alert.js +54 -0
- package/dist/components/avatar/Avatar.d.ts +13 -0
- package/dist/components/avatar/Avatar.js +64 -0
- package/dist/components/background-pattern/BackgroundPatternGrid.d.ts +1 -0
- package/dist/components/background-pattern/BackgroundPatternGrid.js +6 -0
- package/dist/components/badge/Badge.d.ts +1 -1
- package/dist/components/badge/BadgeTestStory.d.ts +1 -1
- package/dist/components/badge/variants/BadgeMore.d.ts +1 -1
- package/dist/components/badge/variants/BadgeMoreTestStory.d.ts +1 -1
- package/dist/components/badge/variants/BadgeTag.d.ts +1 -1
- package/dist/components/banner/Banner.d.ts +9 -0
- package/dist/components/banner/Banner.js +21 -0
- package/dist/components/breadcrumb/Breadcrumb.d.ts +13 -0
- package/dist/components/breadcrumb/Breadcrumb.js +36 -0
- package/dist/components/button/ButtonLoader.d.ts +1 -1
- package/dist/components/button/ButtonTestStory.d.ts +5 -5
- package/dist/components/card/Card.d.ts +1 -1
- package/dist/components/card/Card.stories-ct.d.ts +1 -1
- package/dist/components/card/CardBody.d.ts +1 -1
- package/dist/components/card/CardHeader.d.ts +1 -1
- package/dist/components/chart/chart-legend/ChartLegend.d.ts +38 -0
- package/dist/components/chart/chart-legend/ChartLegend.js +57 -0
- package/dist/components/chart/chart-legend/ChartLegendItem.d.ts +19 -0
- package/dist/components/chart/chart-legend/ChartLegendItem.js +30 -0
- package/dist/components/chart/chart-legend/types.d.ts +49 -0
- package/dist/components/chart/donut-chart/DonutChart.d.ts +55 -0
- package/dist/components/chart/donut-chart/DonutChart.js +110 -0
- package/dist/components/chart/donut-chart/DonutSegments.d.ts +25 -0
- package/dist/components/chart/donut-chart/DonutSegments.js +51 -0
- package/dist/components/chart/donut-chart/donut-tooltip.d.ts +20 -0
- package/dist/components/chart/donut-chart/donut-tooltip.js +37 -0
- package/dist/components/chart/types.d.ts +8 -0
- package/dist/components/checkbox/CheckboxTestStory.d.ts +7 -7
- package/dist/components/collapsible/Collapsible.d.ts +1 -1
- package/dist/components/combobox/Combobox.d.ts +1 -1
- package/dist/components/divider/Divider.d.ts +9 -0
- package/dist/components/divider/Divider.js +28 -0
- package/dist/components/drawer/Drawer.d.ts +8 -0
- package/dist/components/drawer/Drawer.js +68 -0
- package/dist/components/dropdown/Dropdown.d.ts +45 -0
- package/dist/components/dropdown/Dropdown.js +133 -0
- package/dist/components/dropdown/DropdownMenu.d.ts +20 -0
- package/dist/components/dropdown/DropdownMenu.js +78 -0
- package/dist/components/dropdown/DropdownMenuItem.d.ts +13 -0
- package/dist/components/dropdown/DropdownMenuItem.js +49 -0
- package/dist/components/dropdown/DropdownTestStory.d.ts +5 -0
- package/dist/components/dropdown/dropdown-utils.d.ts +4 -0
- package/dist/components/dropdown/dropdown-utils.js +14 -0
- package/dist/components/dropdown/types.d.ts +48 -0
- package/dist/components/dropdown/use-dropdown-keyboard.d.ts +12 -0
- package/dist/components/dropdown/use-dropdown-keyboard.js +49 -0
- package/dist/components/empty-state/EmptyState.d.ts +26 -0
- package/dist/components/empty-state/EmptyState.js +36 -0
- package/dist/components/error-state/ErrorState.d.ts +1 -1
- package/dist/components/featured-icon/FeaturedIcon.d.ts +12 -0
- package/dist/components/featured-icon/FeaturedIcon.js +44 -0
- package/dist/components/form-field/FormField.d.ts +13 -0
- package/dist/components/form-field/FormField.js +21 -0
- package/dist/components/keyboard-shortcut-label/KeyboardShortcutLabel.d.ts +8 -0
- package/dist/components/keyboard-shortcut-label/KeyboardShortcutLabel.js +18 -0
- package/dist/components/loading-state/Loader.d.ts +20 -0
- package/dist/components/loading-state/Loader.js +38 -0
- package/dist/components/loading-state/LoadingState.d.ts +15 -0
- package/dist/components/loading-state/LoadingState.js +47 -0
- package/dist/components/loading-state/locale/en.json.d.ts +6 -0
- package/dist/components/loading-state/locale/en.json.js +7 -0
- package/dist/components/loading-state/locale/vi.json.d.ts +6 -0
- package/dist/components/loading-state/locale/vi.json.js +7 -0
- package/dist/components/media/Media.d.ts +7 -0
- package/dist/components/media/Media.js +25 -0
- package/dist/components/modal/helpers/HeaderIcon.d.ts +1 -1
- package/dist/components/modal/helpers/Title.d.ts +1 -1
- package/dist/components/notification/NotificationBanner.d.ts +9 -0
- package/dist/components/notification/NotificationBanner.js +97 -0
- package/dist/components/notification/icons.d.ts +5 -0
- package/dist/components/notification/icons.js +29 -0
- package/dist/components/notification/index.d.ts +4 -0
- package/dist/components/notification/index.js +26 -0
- package/dist/components/notification/locale/en.json.d.ts +8 -0
- package/dist/components/notification/locale/en.json.js +7 -0
- package/dist/components/notification/locale/vi.json.d.ts +8 -0
- package/dist/components/notification/locale/vi.json.js +7 -0
- package/dist/components/operating-system-icon/OperatingSystemIcon.d.ts +6 -0
- package/dist/components/operating-system-icon/OperatingSystemIcon.js +19 -0
- package/dist/components/operating-system-icon/assets/logo-android.svg.js +5 -0
- package/dist/components/operating-system-icon/assets/logo-apple.svg.js +5 -0
- package/dist/components/operating-system-icon/assets/logo-ubuntu.svg.js +5 -0
- package/dist/components/operating-system-icon/assets/logo-windows-10.svg.js +5 -0
- package/dist/components/page-title/PageTitle.d.ts +1 -1
- package/dist/components/popover/Popover.d.ts +1 -1
- package/dist/components/progress-bar/ProgressBar.d.ts +9 -0
- package/dist/components/progress-bar/ProgressBar.js +31 -0
- package/dist/components/radio/Radio.d.ts +4 -0
- package/dist/components/radio/Radio.js +55 -0
- package/dist/components/searchbox/Searchbox.d.ts +7 -0
- package/dist/components/searchbox/Searchbox.js +15 -0
- package/dist/components/select/Select.d.ts +11 -0
- package/dist/components/select/Select.js +44 -0
- package/dist/components/skeleton/Skeleton.d.ts +14 -0
- package/dist/components/skeleton/Skeleton.js +12 -0
- package/dist/components/switch/Switch.d.ts +1 -1
- package/dist/components/table/Table.d.ts +32 -0
- package/dist/components/table/Table.js +128 -0
- package/dist/components/table/TableActionButton.d.ts +15 -0
- package/dist/components/table/TableActionButton.js +50 -0
- package/dist/components/table/TableCell.d.ts +8 -0
- package/dist/components/table/TableCell.js +26 -0
- package/dist/components/table/TableHeader.d.ts +15 -0
- package/dist/components/table/TableHeader.js +36 -0
- package/dist/components/table/TableHeaderCell.d.ts +10 -0
- package/dist/components/table/TableHeaderCell.js +35 -0
- package/dist/components/table/TablePagination.d.ts +6 -0
- package/dist/components/table/TablePagination.js +69 -0
- package/dist/components/table/TableRow.d.ts +12 -0
- package/dist/components/table/TableRow.js +9 -0
- package/dist/components/table/expandable/ExpandableTable.d.ts +30 -0
- package/dist/components/table/expandable/ExpandableTable.js +156 -0
- package/dist/components/table/hooks/use-fit-page-height.d.ts +14 -0
- package/dist/components/table/hooks/use-fit-page-height.js +21 -0
- package/dist/components/table/hooks/use-row-selection.d.ts +27 -0
- package/dist/components/table/hooks/use-row-selection.js +35 -0
- package/dist/components/table/locale/en.json.d.ts +13 -0
- package/dist/components/table/locale/en.json.js +21 -0
- package/dist/components/table/locale/vi.json.d.ts +13 -0
- package/dist/components/table/locale/vi.json.js +21 -0
- package/dist/components/table/table-utils.d.ts +10 -0
- package/dist/components/table/table-utils.js +10 -0
- package/dist/components/table/types.d.ts +84 -0
- package/dist/components/tabs/Tabs.d.ts +27 -0
- package/dist/components/tabs/Tabs.js +75 -0
- package/dist/components/tabs/TabsTestStory.d.ts +4 -0
- package/dist/components/tags-input/TagsInput.d.ts +18 -0
- package/dist/components/tags-input/TagsInput.js +78 -0
- package/dist/components/tags-input/TagsInputTestStory.d.ts +3 -0
- package/dist/components/textarea/Textarea.d.ts +7 -0
- package/dist/components/textarea/Textarea.js +36 -0
- package/dist/components/toast/ToastSlice.d.ts +1 -1
- package/dist/components/toast/index.d.ts +1 -1
- package/dist/components/tooltip/Tooltip.d.ts +1 -1
- package/dist/filters/FilterDropdown.d.ts +9 -0
- package/dist/filters/FilterDropdown.js +57 -0
- package/dist/filters/types.d.ts +11 -0
- package/dist/filters/url-params.d.ts +5 -0
- package/dist/filters/url-params.js +20 -0
- package/dist/filters/use-filters.d.ts +13 -0
- package/dist/filters/use-filters.js +63 -0
- package/dist/hooks/use-countdown.d.ts +4 -0
- package/dist/hooks/use-countdown.js +18 -0
- package/dist/i18n/resources.js +23 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +122 -40
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +421 -350
- package/dist/utils/key-typeguard.d.ts +5 -0
- package/dist/utils/key-typeguard.js +6 -0
- package/dist/utils/use-debounce.d.ts +1 -0
- package/dist/utils/use-debounce.js +11 -0
- package/package.json +28 -6
- package/theme.css +4 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DropdownProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Generic standalone dropdown for action menus, context menus, or selection lists.
|
|
4
|
+
*
|
|
5
|
+
* Supports controlled (`open`) and uncontrolled (`defaultOpen`) open state.
|
|
6
|
+
* When `selected` is provided, the dropdown shows checkmarks (selection mode).
|
|
7
|
+
* Otherwise it behaves as a plain action menu.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Action menu
|
|
11
|
+
* <Dropdown
|
|
12
|
+
* items={[
|
|
13
|
+
* { id: "edit", label: "Edit", icon: <Edit01 /> },
|
|
14
|
+
* { type: "divider" },
|
|
15
|
+
* { id: "delete", label: "Delete", danger: true },
|
|
16
|
+
* ]}
|
|
17
|
+
* onSelect={(item) => handleAction(item.id)}
|
|
18
|
+
* >
|
|
19
|
+
* <IconButton icon={<DotsVertical />} />
|
|
20
|
+
* </Dropdown>
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Selection dropdown with checkmarks
|
|
24
|
+
* <Dropdown
|
|
25
|
+
* items={statusOptions}
|
|
26
|
+
* selected={currentStatus}
|
|
27
|
+
* onSelect={(item) => setStatus(item.id)}
|
|
28
|
+
* syncWidth
|
|
29
|
+
* >
|
|
30
|
+
* <Button>{currentStatusLabel} <ChevronDown /></Button>
|
|
31
|
+
* </Dropdown>
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Custom item rendering
|
|
35
|
+
* <Dropdown
|
|
36
|
+
* items={[
|
|
37
|
+
* { id: "high", label: "High", render: () => <Badge color="error">High</Badge> },
|
|
38
|
+
* { id: "low", label: "Low", render: () => <Badge color="success">Low</Badge> },
|
|
39
|
+
* ]}
|
|
40
|
+
* onSelect={handleSelect}
|
|
41
|
+
* >
|
|
42
|
+
* <Button>Priority</Button>
|
|
43
|
+
* </Dropdown>
|
|
44
|
+
*/
|
|
45
|
+
export declare const Dropdown: ({ items, onSelect, selected, open: openProp, defaultOpen, onOpenChange, placement, syncWidth, children, menuClassName, className, disabled, }: DropdownProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { jsxs as C, Fragment as G, jsx as I } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as b, useState as J, useMemo as P, useCallback as i, useEffect as g } from "react";
|
|
3
|
+
import { cn as Q } from "../../utils/cn.js";
|
|
4
|
+
import { usePopoverCoord as U } from "../popover/use-popover-coord.js";
|
|
5
|
+
import { DropdownMenu as V } from "./DropdownMenu.js";
|
|
6
|
+
import { flattenItems as W } from "./dropdown-utils.js";
|
|
7
|
+
import { useDropdownKeyboard as X } from "./use-dropdown-keyboard.js";
|
|
8
|
+
const oe = ({
|
|
9
|
+
items: d,
|
|
10
|
+
onSelect: m,
|
|
11
|
+
selected: r,
|
|
12
|
+
open: k,
|
|
13
|
+
defaultOpen: A = !1,
|
|
14
|
+
onOpenChange: p,
|
|
15
|
+
placement: K = "bottomLeft",
|
|
16
|
+
syncWidth: S = !1,
|
|
17
|
+
children: L,
|
|
18
|
+
menuClassName: R,
|
|
19
|
+
className: T,
|
|
20
|
+
disabled: a = !1
|
|
21
|
+
}) => {
|
|
22
|
+
const f = b(null), v = b(
|
|
23
|
+
`dropdown-menu-${Math.random().toString(36).slice(2, 9)}`
|
|
24
|
+
).current, h = b(null), y = k !== void 0, [j, H] = J(A), n = y ? k : j, { style: N } = U(f, h, {
|
|
25
|
+
position: K,
|
|
26
|
+
syncWidth: S
|
|
27
|
+
}), { activeId: w, setActiveId: q, handleNavigationKeyDown: x, resetActive: c } = X(d), B = P(() => r === void 0 ? /* @__PURE__ */ new Set() : Array.isArray(r) ? new Set(r) : /* @__PURE__ */ new Set([r]), [r]), F = r !== void 0, s = i(
|
|
28
|
+
(e) => {
|
|
29
|
+
y || H(e), p == null || p(e);
|
|
30
|
+
},
|
|
31
|
+
[y, p]
|
|
32
|
+
), t = i(() => {
|
|
33
|
+
s(!1), c();
|
|
34
|
+
}, [s, c]), D = i(
|
|
35
|
+
(e) => {
|
|
36
|
+
var o, u;
|
|
37
|
+
m == null || m(e), t(), (u = ((o = f.current) == null ? void 0 : o.querySelector(
|
|
38
|
+
'button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
39
|
+
)) ?? f.current) == null || u.focus();
|
|
40
|
+
},
|
|
41
|
+
[m, t]
|
|
42
|
+
), $ = i(() => {
|
|
43
|
+
a || s(!n);
|
|
44
|
+
}, [a, n, s]), E = i(
|
|
45
|
+
(e) => {
|
|
46
|
+
if (!a) {
|
|
47
|
+
if (!n && ["ArrowDown", "Enter", " "].includes(e.key)) {
|
|
48
|
+
e.preventDefault(), s(!0);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (n) {
|
|
52
|
+
if (e.key === "Escape") {
|
|
53
|
+
e.preventDefault(), t();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (e.key === "Tab") {
|
|
57
|
+
t();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if ((e.key === "Enter" || e.key === " ") && w !== null) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
const l = W(d).find((o) => o.id === w);
|
|
63
|
+
l && D(l);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
x(e);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
[
|
|
71
|
+
a,
|
|
72
|
+
n,
|
|
73
|
+
s,
|
|
74
|
+
t,
|
|
75
|
+
D,
|
|
76
|
+
w,
|
|
77
|
+
x,
|
|
78
|
+
d
|
|
79
|
+
]
|
|
80
|
+
), z = i((e) => {
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
}, []);
|
|
83
|
+
return g(() => {
|
|
84
|
+
if (!n) return;
|
|
85
|
+
function e(l) {
|
|
86
|
+
const o = l.target, u = f.current, M = document.getElementById(v);
|
|
87
|
+
u != null && u.contains(o) || M != null && M.contains(o) || t();
|
|
88
|
+
}
|
|
89
|
+
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
90
|
+
}, [n, v, t]), g(() => {
|
|
91
|
+
n || c();
|
|
92
|
+
}, [n, c]), /* @__PURE__ */ C(G, { children: [
|
|
93
|
+
/* @__PURE__ */ I(
|
|
94
|
+
"span",
|
|
95
|
+
{
|
|
96
|
+
ref: f,
|
|
97
|
+
"aria-haspopup": "menu",
|
|
98
|
+
"aria-expanded": n,
|
|
99
|
+
"aria-controls": n ? v : void 0,
|
|
100
|
+
className: Q(
|
|
101
|
+
"inline-flex",
|
|
102
|
+
a && "cursor-not-allowed",
|
|
103
|
+
T
|
|
104
|
+
),
|
|
105
|
+
onClick: $,
|
|
106
|
+
onKeyDown: E,
|
|
107
|
+
children: L
|
|
108
|
+
}
|
|
109
|
+
),
|
|
110
|
+
/* @__PURE__ */ I(
|
|
111
|
+
V,
|
|
112
|
+
{
|
|
113
|
+
entries: d,
|
|
114
|
+
isOpen: n,
|
|
115
|
+
style: N,
|
|
116
|
+
menuRef: h,
|
|
117
|
+
menuClassName: R,
|
|
118
|
+
selectedSet: B,
|
|
119
|
+
selectionMode: F,
|
|
120
|
+
activeId: w,
|
|
121
|
+
menuId: v,
|
|
122
|
+
onSelect: D,
|
|
123
|
+
onHoverEnter: q,
|
|
124
|
+
onHoverLeave: c,
|
|
125
|
+
onKeyDown: E,
|
|
126
|
+
onMouseDown: z
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
] });
|
|
130
|
+
};
|
|
131
|
+
export {
|
|
132
|
+
oe as Dropdown
|
|
133
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CSSProperties, RefObject } from 'react';
|
|
2
|
+
import { DropdownEntry, DropdownItem } from './types';
|
|
3
|
+
interface DropdownMenuProps {
|
|
4
|
+
entries: DropdownEntry[];
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
style: CSSProperties | undefined;
|
|
7
|
+
menuRef: RefObject<HTMLDivElement>;
|
|
8
|
+
menuClassName?: string;
|
|
9
|
+
selectedSet: Set<string>;
|
|
10
|
+
selectionMode: boolean;
|
|
11
|
+
activeId: string | null;
|
|
12
|
+
menuId: string;
|
|
13
|
+
onSelect: (item: DropdownItem) => void;
|
|
14
|
+
onHoverEnter: (id: string) => void;
|
|
15
|
+
onHoverLeave: () => void;
|
|
16
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
17
|
+
onMouseDown: (e: React.MouseEvent) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const DropdownMenu: ({ entries, isOpen, style, menuRef, menuClassName, selectedSet, selectionMode, activeId, menuId, onSelect, onHoverEnter, onHoverLeave, onKeyDown, onMouseDown, }: DropdownMenuProps) => import('react').ReactPortal;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx as r, jsxs as w } from "react/jsx-runtime";
|
|
2
|
+
import { createPortal as N } from "react-dom";
|
|
3
|
+
import { cn as $ } from "../../utils/cn.js";
|
|
4
|
+
import { DropdownMenuItem as m } from "./DropdownMenuItem.js";
|
|
5
|
+
const z = ({
|
|
6
|
+
entries: u,
|
|
7
|
+
isOpen: c,
|
|
8
|
+
style: n,
|
|
9
|
+
menuRef: v,
|
|
10
|
+
menuClassName: b,
|
|
11
|
+
selectedSet: d,
|
|
12
|
+
selectionMode: a,
|
|
13
|
+
activeId: e,
|
|
14
|
+
menuId: f,
|
|
15
|
+
onSelect: s,
|
|
16
|
+
onHoverEnter: p,
|
|
17
|
+
onHoverLeave: t,
|
|
18
|
+
onKeyDown: g,
|
|
19
|
+
onMouseDown: h
|
|
20
|
+
}) => {
|
|
21
|
+
const x = /* @__PURE__ */ r(
|
|
22
|
+
"div",
|
|
23
|
+
{
|
|
24
|
+
ref: v,
|
|
25
|
+
id: f,
|
|
26
|
+
role: "menu",
|
|
27
|
+
"aria-activedescendant": e ?? void 0,
|
|
28
|
+
className: $(
|
|
29
|
+
"z-20 rounded-lg border border-gray-v2-200 bg-white p-1 shadow-lg transition-all",
|
|
30
|
+
"max-h-[40vh] overflow-auto",
|
|
31
|
+
!c && "invisible pointer-events-none scale-95 opacity-0",
|
|
32
|
+
b
|
|
33
|
+
),
|
|
34
|
+
style: n,
|
|
35
|
+
onKeyDown: g,
|
|
36
|
+
onMouseDown: h,
|
|
37
|
+
children: u.map((i, l) => "type" in i && i.type === "divider" ? /* @__PURE__ */ r(
|
|
38
|
+
"div",
|
|
39
|
+
{
|
|
40
|
+
role: "separator",
|
|
41
|
+
className: "my-1 border-t border-gray-v2-200"
|
|
42
|
+
},
|
|
43
|
+
`divider-${l}`
|
|
44
|
+
) : "type" in i && i.type === "group" ? /* @__PURE__ */ w("div", { role: "group", children: [
|
|
45
|
+
/* @__PURE__ */ r("div", { className: "px-2 py-1.5 text-xs font-medium text-gray-v2-500", children: i.label }),
|
|
46
|
+
i.items.map((o) => /* @__PURE__ */ r(
|
|
47
|
+
m,
|
|
48
|
+
{
|
|
49
|
+
item: o,
|
|
50
|
+
isSelected: d.has(o.id),
|
|
51
|
+
isActive: e === o.id,
|
|
52
|
+
selectionMode: a,
|
|
53
|
+
onSelect: s,
|
|
54
|
+
onHoverEnter: p,
|
|
55
|
+
onHoverLeave: t
|
|
56
|
+
},
|
|
57
|
+
o.id
|
|
58
|
+
))
|
|
59
|
+
] }, `group-${i.label}-${l}`) : /* @__PURE__ */ r(
|
|
60
|
+
m,
|
|
61
|
+
{
|
|
62
|
+
item: i,
|
|
63
|
+
isSelected: d.has(i.id),
|
|
64
|
+
isActive: e === i.id,
|
|
65
|
+
selectionMode: a,
|
|
66
|
+
onSelect: s,
|
|
67
|
+
onHoverEnter: p,
|
|
68
|
+
onHoverLeave: t
|
|
69
|
+
},
|
|
70
|
+
i.id
|
|
71
|
+
))
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
return N(x, document.body);
|
|
75
|
+
};
|
|
76
|
+
export {
|
|
77
|
+
z as DropdownMenu
|
|
78
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DropdownItem } from './types';
|
|
2
|
+
interface DropdownMenuItemProps {
|
|
3
|
+
item: DropdownItem;
|
|
4
|
+
isSelected: boolean;
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
/** Whether the dropdown is in selection mode (shows checkmarks). */
|
|
7
|
+
selectionMode: boolean;
|
|
8
|
+
onSelect: (item: DropdownItem) => void;
|
|
9
|
+
onHoverEnter: (id: string) => void;
|
|
10
|
+
onHoverLeave: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const DropdownMenuItem: ({ item, isSelected, isActive, selectionMode, onSelect, onHoverEnter, onHoverLeave, }: DropdownMenuItemProps) => import("react").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as r, jsxs as a, Fragment as c } from "react/jsx-runtime";
|
|
2
|
+
import { Check as p } from "@untitled-ui/icons-react";
|
|
3
|
+
import { cn as b } from "../../utils/cn.js";
|
|
4
|
+
import { getDropdownItemId as f } from "./dropdown-utils.js";
|
|
5
|
+
const h = ({
|
|
6
|
+
item: e,
|
|
7
|
+
isSelected: n,
|
|
8
|
+
isActive: o,
|
|
9
|
+
selectionMode: l,
|
|
10
|
+
onSelect: s,
|
|
11
|
+
onHoverEnter: d,
|
|
12
|
+
onHoverLeave: t
|
|
13
|
+
}) => {
|
|
14
|
+
const i = e.render ? e.render() : /* @__PURE__ */ r(m, { item: e });
|
|
15
|
+
return /* @__PURE__ */ a(
|
|
16
|
+
"div",
|
|
17
|
+
{
|
|
18
|
+
role: "menuitem",
|
|
19
|
+
"aria-label": e.label,
|
|
20
|
+
"aria-disabled": e.disabled || void 0,
|
|
21
|
+
id: f(e.id),
|
|
22
|
+
className: b(
|
|
23
|
+
"flex items-center justify-between gap-2 rounded-md p-2 pr-2.5 text-sm font-semibold",
|
|
24
|
+
e.disabled ? "cursor-not-allowed opacity-50" : [
|
|
25
|
+
"cursor-pointer",
|
|
26
|
+
e.danger ? "text-error-v2-700" : "text-gray-v2-700",
|
|
27
|
+
n ? "bg-gray-v2-50 text-gray-v2-700" : o ? "bg-gray-v2-100" : "hover:bg-gray-v2-50"
|
|
28
|
+
]
|
|
29
|
+
),
|
|
30
|
+
onClick: () => {
|
|
31
|
+
e.disabled || s(e);
|
|
32
|
+
},
|
|
33
|
+
onMouseEnter: () => {
|
|
34
|
+
e.disabled || d(e.id);
|
|
35
|
+
},
|
|
36
|
+
onMouseLeave: t,
|
|
37
|
+
children: [
|
|
38
|
+
/* @__PURE__ */ r("div", { className: "flex min-w-0 items-center gap-2 overflow-hidden text-ellipsis", children: i }),
|
|
39
|
+
l ? n ? /* @__PURE__ */ r(p, { className: "h-5 w-5 min-w-5 text-brand-v2-600" }) : /* @__PURE__ */ r("div", { className: "w-5" }) : null
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}, m = ({ item: e }) => /* @__PURE__ */ a(c, { children: [
|
|
44
|
+
e.icon ? /* @__PURE__ */ r("span", { className: "flex h-5 w-5 items-center justify-center", children: e.icon }) : null,
|
|
45
|
+
/* @__PURE__ */ r("span", { className: "truncate", children: e.label })
|
|
46
|
+
] });
|
|
47
|
+
export {
|
|
48
|
+
h as DropdownMenuItem
|
|
49
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const DropdownWithCallback: () => import("react").JSX.Element;
|
|
2
|
+
export declare const DropdownWithSelection: () => import("react").JSX.Element;
|
|
3
|
+
export declare const DropdownWithDisabledItem: () => import("react").JSX.Element;
|
|
4
|
+
export declare const DropdownWithGroups: () => import("react").JSX.Element;
|
|
5
|
+
export declare const DropdownDisabled: () => import("react").JSX.Element;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { DropdownEntry, DropdownItem } from './types';
|
|
2
|
+
export declare function getDropdownItemId(id: string): string;
|
|
3
|
+
/** Flatten entries into a list of actionable (non-disabled) items. */
|
|
4
|
+
export declare function flattenItems(entries: DropdownEntry[]): DropdownItem[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function i(e) {
|
|
2
|
+
return `dropdown-item-${e}`;
|
|
3
|
+
}
|
|
4
|
+
function o(e) {
|
|
5
|
+
return e.flatMap(
|
|
6
|
+
(t) => "type" in t && t.type === "group" ? t.items : [t]
|
|
7
|
+
).filter(
|
|
8
|
+
(t) => !("type" in t) && !t.disabled
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
o as flattenItems,
|
|
13
|
+
i as getDropdownItemId
|
|
14
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface DropdownItem {
|
|
3
|
+
id: string;
|
|
4
|
+
/** Plain text label — used for accessibility and keyboard type-ahead. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Custom visual override. When provided, replaces the default icon + label rendering. */
|
|
7
|
+
render?: () => ReactNode;
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** Render with destructive styling (red text). */
|
|
11
|
+
danger?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface DropdownGroup {
|
|
14
|
+
type: "group";
|
|
15
|
+
label: string;
|
|
16
|
+
items: DropdownItem[];
|
|
17
|
+
}
|
|
18
|
+
export interface DropdownDivider {
|
|
19
|
+
type: "divider";
|
|
20
|
+
}
|
|
21
|
+
export type DropdownEntry = DropdownItem | DropdownGroup | DropdownDivider;
|
|
22
|
+
export type DropdownPlacement = "bottomLeft" | "bottomRight" | "topLeft" | "topRight";
|
|
23
|
+
export interface DropdownProps {
|
|
24
|
+
/** Menu entries: items, groups, and dividers. */
|
|
25
|
+
items: DropdownEntry[];
|
|
26
|
+
/** Called when an item is clicked. */
|
|
27
|
+
onSelect?: (item: DropdownItem) => void;
|
|
28
|
+
/** Currently selected item id(s). When provided, shows checkmarks. */
|
|
29
|
+
selected?: string | string[];
|
|
30
|
+
/** Controlled open state. */
|
|
31
|
+
open?: boolean;
|
|
32
|
+
/** Initial open state for uncontrolled mode. Default: false. */
|
|
33
|
+
defaultOpen?: boolean;
|
|
34
|
+
/** Callback when open state changes. */
|
|
35
|
+
onOpenChange?: (open: boolean) => void;
|
|
36
|
+
/** Preferred placement. Auto-flips when near viewport edge. Default: "bottomLeft". */
|
|
37
|
+
placement?: DropdownPlacement;
|
|
38
|
+
/** Sync menu width to trigger width. Default: false. */
|
|
39
|
+
syncWidth?: boolean;
|
|
40
|
+
/** The trigger element. */
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
/** Additional classes on the menu panel. */
|
|
43
|
+
menuClassName?: string;
|
|
44
|
+
/** Additional classes on the trigger wrapper. */
|
|
45
|
+
className?: string;
|
|
46
|
+
/** Disable the dropdown entirely. */
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DropdownEntry } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Manages keyboard navigation state for dropdown items.
|
|
4
|
+
* Only handles ArrowUp/Down/Home/End navigation — the parent is responsible
|
|
5
|
+
* for acting on Enter/Escape/Tab via the returned `activeId`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useDropdownKeyboard(entries: DropdownEntry[]): {
|
|
8
|
+
activeId: string | null;
|
|
9
|
+
setActiveId: import('react').Dispatch<import('react').SetStateAction<string | null>>;
|
|
10
|
+
handleNavigationKeyDown: (e: React.KeyboardEvent) => void;
|
|
11
|
+
resetActive: () => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useState as f, useMemo as p, useCallback as l } from "react";
|
|
2
|
+
import { flattenItems as g, getDropdownItemId as m } from "./dropdown-utils.js";
|
|
3
|
+
function w(d) {
|
|
4
|
+
const [o, a] = f(null), e = p(() => g(d), [d]), c = l(() => o === null ? -1 : e.findIndex((t) => t.id === o), [o, e]), r = l(
|
|
5
|
+
(t) => {
|
|
6
|
+
if (e.length === 0) return;
|
|
7
|
+
const n = (t % e.length + e.length) % e.length;
|
|
8
|
+
a(e[n].id);
|
|
9
|
+
const s = document.getElementById(
|
|
10
|
+
m(e[n].id)
|
|
11
|
+
);
|
|
12
|
+
s == null || s.scrollIntoView({ block: "nearest" });
|
|
13
|
+
},
|
|
14
|
+
[e]
|
|
15
|
+
), i = l(
|
|
16
|
+
(t) => {
|
|
17
|
+
if (e.length !== 0)
|
|
18
|
+
switch (t.key) {
|
|
19
|
+
case "ArrowDown": {
|
|
20
|
+
t.preventDefault();
|
|
21
|
+
const n = c();
|
|
22
|
+
r(n + 1);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
case "ArrowUp": {
|
|
26
|
+
t.preventDefault();
|
|
27
|
+
const n = c();
|
|
28
|
+
r(n === -1 ? e.length - 1 : n - 1);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "Home": {
|
|
32
|
+
t.preventDefault(), r(0);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case "End": {
|
|
36
|
+
t.preventDefault(), r(e.length - 1);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
[e, c, r]
|
|
42
|
+
), u = l(() => {
|
|
43
|
+
a(null);
|
|
44
|
+
}, []);
|
|
45
|
+
return { activeId: o, setActiveId: a, handleNavigationKeyDown: i, resetActive: u };
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
w as useDropdownKeyboard
|
|
49
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
title: string;
|
|
4
|
+
supportingText?: string;
|
|
5
|
+
/**
|
|
6
|
+
* - `"illustration"`: cloud graphic with grid background (default)
|
|
7
|
+
* - `"featured-icon"`: icon in a bordered box with circles background
|
|
8
|
+
* @default "illustration"
|
|
9
|
+
*/
|
|
10
|
+
type?: "featured-icon" | "illustration";
|
|
11
|
+
buttons?: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Override the default SearchLg icon for `type="featured-icon"`. */
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generic empty state for lists, tables, and sections.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <EmptyState title="No results" supportingText="Try a different filter." type="featured-icon" />
|
|
22
|
+
* <EmptyState title="Nothing here yet" buttons={<Button>Add item</Button>} />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const EmptyState: ({ title, supportingText, type, buttons, className, icon, }: Props) => import("react").JSX.Element;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsxs as l, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { SearchLg as o } from "@untitled-ui/icons-react";
|
|
3
|
+
import { cn as m } from "../../utils/cn.js";
|
|
4
|
+
import n from "../../assets/background-pattern-grid.svg.js";
|
|
5
|
+
import d from "../../assets/background-pattern-circles-md.svg.js";
|
|
6
|
+
import f from "../../assets/empty-cloud.svg.js";
|
|
7
|
+
const N = ({
|
|
8
|
+
title: s,
|
|
9
|
+
supportingText: r,
|
|
10
|
+
type: t = "illustration",
|
|
11
|
+
buttons: a,
|
|
12
|
+
className: i,
|
|
13
|
+
icon: c
|
|
14
|
+
}) => /* @__PURE__ */ l(
|
|
15
|
+
"div",
|
|
16
|
+
{
|
|
17
|
+
className: m(
|
|
18
|
+
"relative flex flex-1 flex-col items-center justify-center gap-8 overflow-hidden pb-6 pt-12",
|
|
19
|
+
i
|
|
20
|
+
),
|
|
21
|
+
children: [
|
|
22
|
+
t === "illustration" ? /* @__PURE__ */ e(n, { className: "absolute -top-1/3 h-120 w-120" }) : /* @__PURE__ */ e(d, { className: "absolute -top-[10.55rem] h-120 w-120" }),
|
|
23
|
+
/* @__PURE__ */ l("div", { className: "z-10 flex flex-col items-center gap-5", children: [
|
|
24
|
+
t === "illustration" ? /* @__PURE__ */ e(f, { className: "h-32 w-43" }) : /* @__PURE__ */ e("div", { className: "flex h-12 w-12 items-center justify-center rounded-lg border border-gray-v2-200 bg-white shadow-xs", children: c ?? /* @__PURE__ */ e(o, { className: "h-6 w-6" }) }),
|
|
25
|
+
/* @__PURE__ */ l("div", { className: "flex flex-col items-center gap-2 px-3 text-center", children: [
|
|
26
|
+
/* @__PURE__ */ e("span", { className: "text-lg font-semibold text-gray-v2-700", children: s }),
|
|
27
|
+
r ? /* @__PURE__ */ e("span", { className: "text-sm text-gray-v2", children: r }) : null
|
|
28
|
+
] })
|
|
29
|
+
] }),
|
|
30
|
+
a ? /* @__PURE__ */ e("div", { className: "flex gap-3", children: a }) : null
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
export {
|
|
35
|
+
N as EmptyState
|
|
36
|
+
};
|
|
@@ -5,5 +5,5 @@ interface Props {
|
|
|
5
5
|
buttons?: ReactNode;
|
|
6
6
|
className?: string;
|
|
7
7
|
}
|
|
8
|
-
export declare const ErrorState: ({ title, supportingText, buttons, className, }: Props) => import("react
|
|
8
|
+
export declare const ErrorState: ({ title, supportingText, buttons, className, }: Props) => import("react").JSX.Element;
|
|
9
9
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactNode, SVGProps } from 'react';
|
|
2
|
+
type FeaturedIconSize = "md" | "lg";
|
|
3
|
+
interface Props {
|
|
4
|
+
Icon: (props: SVGProps<SVGSVGElement>) => ReactNode;
|
|
5
|
+
size?: FeaturedIconSize;
|
|
6
|
+
/** Use when the surrounding background is dark, so the glass overlay stays legible. */
|
|
7
|
+
darkMode?: boolean;
|
|
8
|
+
backgroundClassName?: string;
|
|
9
|
+
iconClassName?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare const FeaturedIcon: ({ Icon, size, darkMode, backgroundClassName, iconClassName, }: Props) => import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsxs as a, jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { cn as e } from "../../utils/cn.js";
|
|
3
|
+
const d = {
|
|
4
|
+
md: "size-10 min-w-10",
|
|
5
|
+
lg: "size-12 min-w-12"
|
|
6
|
+
}, u = ({
|
|
7
|
+
Icon: r,
|
|
8
|
+
size: l = "md",
|
|
9
|
+
darkMode: i = !1,
|
|
10
|
+
backgroundClassName: o,
|
|
11
|
+
iconClassName: s
|
|
12
|
+
}) => /* @__PURE__ */ a(
|
|
13
|
+
"div",
|
|
14
|
+
{
|
|
15
|
+
className: e(
|
|
16
|
+
"relative flex items-center justify-center",
|
|
17
|
+
d[l]
|
|
18
|
+
),
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ t(
|
|
21
|
+
"div",
|
|
22
|
+
{
|
|
23
|
+
className: e(
|
|
24
|
+
"absolute -top-[8%] left-[4%] origin-bottom-right rotate-15 h-full w-full rounded-lg bg-brand-v2-700",
|
|
25
|
+
o
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
/* @__PURE__ */ t(
|
|
30
|
+
"div",
|
|
31
|
+
{
|
|
32
|
+
className: e(
|
|
33
|
+
"h-full w-full min-w-full border rounded-lg backdrop-blur-sm",
|
|
34
|
+
i ? "bg-white/40 border-white/40" : "bg-white/60 border-white/60"
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
/* @__PURE__ */ t(r, { className: e("absolute h-1/2 w-1/2 text-white", s) })
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
export {
|
|
43
|
+
u as FeaturedIcon
|
|
44
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
label: ReactNode;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** id of the associated control — wires up htmlFor for accessibility */
|
|
6
|
+
htmlFor: string;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
error?: ReactNode;
|
|
9
|
+
hint?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const FormField: ({ label, children, htmlFor, required, error, hint, className, }: Props) => import("react").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsxs as t, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { cn as n } from "../../utils/cn.js";
|
|
3
|
+
const o = ({
|
|
4
|
+
label: a,
|
|
5
|
+
children: m,
|
|
6
|
+
htmlFor: r,
|
|
7
|
+
required: c,
|
|
8
|
+
error: l,
|
|
9
|
+
hint: s,
|
|
10
|
+
className: x
|
|
11
|
+
}) => /* @__PURE__ */ t("div", { className: n("flex flex-col gap-1.5 w-full", x), children: [
|
|
12
|
+
/* @__PURE__ */ t("label", { htmlFor: r, className: "text-sm font-medium text-gray-v2-700", children: [
|
|
13
|
+
a,
|
|
14
|
+
c && /* @__PURE__ */ e("span", { className: "ml-0.5 text-brand-v2-600", children: "*" })
|
|
15
|
+
] }),
|
|
16
|
+
m,
|
|
17
|
+
l ? /* @__PURE__ */ e("p", { className: "text-sm text-error-v2-600", children: l }) : s ? /* @__PURE__ */ e("p", { className: "text-sm text-gray-v2-600", children: s }) : null
|
|
18
|
+
] });
|
|
19
|
+
export {
|
|
20
|
+
o as FormField
|
|
21
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReactNode, SVGProps } from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
name: string;
|
|
4
|
+
Icon?: (props: SVGProps<SVGSVGElement>) => ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const KeyboardShortcutLabel: ({ name, Icon, className }: Props) => import("react").JSX.Element;
|
|
8
|
+
export {};
|