@socprime/react-ui 0.0.5
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/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +537 -0
- package/attack-flow.d.ts +16 -0
- package/charts.d.ts +32 -0
- package/decorators/index.js +8 -0
- package/decorators/withRouter.js +10 -0
- package/decorators/withTheme.js +10 -0
- package/decorators.d.ts +10 -0
- package/domain.d.ts +23 -0
- package/editor.d.ts +25 -0
- package/index.d.ts +702 -0
- package/lib/cn.js +8 -0
- package/lib/theme.js +26 -0
- package/lib/useFullscreen.js +52 -0
- package/lib/useListenOnResizeDebounce.js +22 -0
- package/lib/useThemeColors.js +39 -0
- package/package.json +113 -0
- package/preset/createConfig.js +98 -0
- package/preset/createPreview.js +53 -0
- package/preset/index.js +6 -0
- package/preset/restoreNativeFocus.js +33 -0
- package/preset/types.js +0 -0
- package/preset.d.ts +27 -0
- package/theme-9m7j1UoI.d.ts +5 -0
- package/ui/Accordion/Accordion.js +82 -0
- package/ui/Accordion/AccordionSection.js +41 -0
- package/ui/Accordion/FolderTreeExpandTrigger.js +29 -0
- package/ui/Accordion/chevronVariants.js +31 -0
- package/ui/Accordion/index.js +16 -0
- package/ui/AnimatedDots/AnimatedDots.js +10 -0
- package/ui/AnimatedDots/index.js +4 -0
- package/ui/Aside/Aside.js +34 -0
- package/ui/Aside/index.js +4 -0
- package/ui/AttackFlow/AttackFlow.js +9 -0
- package/ui/AttackFlow/AttackFlowLayout.js +63 -0
- package/ui/AttackFlow/Controls.js +42 -0
- package/ui/AttackFlow/Node.js +47 -0
- package/ui/AttackFlow/OtherNode.js +44 -0
- package/ui/AttackFlow/index.js +4 -0
- package/ui/AttackFlow/prependData.js +153 -0
- package/ui/AttackFlow/types.js +0 -0
- package/ui/AttackFlow/useAttackFlow.js +193 -0
- package/ui/Badge/Badge.js +57 -0
- package/ui/Badge/index.js +5 -0
- package/ui/Button/Button.css +1 -0
- package/ui/Button/Button.js +109 -0
- package/ui/Button/index.js +5 -0
- package/ui/Charts/AreaChartWithGradient.js +79 -0
- package/ui/Charts/index.js +4 -0
- package/ui/Checkbox/Checkbox.js +31 -0
- package/ui/Checkbox/index.js +4 -0
- package/ui/ConditionalContent/ConditionalContent.js +10 -0
- package/ui/ConditionalContent/index.js +4 -0
- package/ui/CorrelationTimer/CorrelationTimer.js +62 -0
- package/ui/CorrelationTimer/index.js +4 -0
- package/ui/DeleteButtonConfirm/DeleteButtonConfirm.js +65 -0
- package/ui/DeleteButtonConfirm/index.js +4 -0
- package/ui/Dialog/ConfirmDialog.js +54 -0
- package/ui/Dialog/DefaultDialog.js +82 -0
- package/ui/Dialog/Dialog.js +120 -0
- package/ui/Dialog/index.js +32 -0
- package/ui/Dropdown/Dropdown.js +204 -0
- package/ui/Dropdown/DropdownsCheckbox.js +102 -0
- package/ui/Dropdown/DropdownsSelect.js +97 -0
- package/ui/Dropdown/index.js +38 -0
- package/ui/Editor/Editor.js +97 -0
- package/ui/Editor/index.js +4 -0
- package/ui/Editor/monacoSetup.js +38 -0
- package/ui/Editor/theme.js +50 -0
- package/ui/Editor/types.js +0 -0
- package/ui/EmptyState/EmptyState.js +26 -0
- package/ui/EmptyState/index.js +4 -0
- package/ui/Field/Field.js +204 -0
- package/ui/Field/index.js +24 -0
- package/ui/HelperText/HelperText.js +7 -0
- package/ui/HelperText/index.js +4 -0
- package/ui/Input/Input.js +40 -0
- package/ui/Input/index.js +4 -0
- package/ui/InputNumber/InputNumber.js +90 -0
- package/ui/InputNumber/index.js +4 -0
- package/ui/InputPassword/InputPassword.js +30 -0
- package/ui/InputPassword/index.js +4 -0
- package/ui/Label/Label.js +13 -0
- package/ui/Label/LabelInfo.js +14 -0
- package/ui/Label/index.js +6 -0
- package/ui/MultiSelect/MultiSelect.js +163 -0
- package/ui/MultiSelect/index.js +4 -0
- package/ui/PageHeader/PageHeader.js +51 -0
- package/ui/PageHeader/index.js +4 -0
- package/ui/Pagination/Pagination.js +97 -0
- package/ui/Pagination/PaginationWrap.js +149 -0
- package/ui/Pagination/index.js +20 -0
- package/ui/RadioGroup/RadioGroup.js +45 -0
- package/ui/RadioGroup/index.js +5 -0
- package/ui/ScrollArea/ScrollArea.js +57 -0
- package/ui/ScrollArea/index.js +5 -0
- package/ui/SearchInput/SearchInput.js +38 -0
- package/ui/SearchInput/index.js +4 -0
- package/ui/SearchInputFields/SearchInputFields.js +53 -0
- package/ui/SearchInputFields/index.js +4 -0
- package/ui/Select/Select.js +155 -0
- package/ui/Select/SelectDefault.js +43 -0
- package/ui/Select/index.js +26 -0
- package/ui/Separator/Separator.js +26 -0
- package/ui/Separator/index.js +4 -0
- package/ui/Severity/Severity.js +11 -0
- package/ui/Severity/index.js +4 -0
- package/ui/Severity/utils.js +53 -0
- package/ui/Skeleton/Skeleton.js +25 -0
- package/ui/Skeleton/index.js +5 -0
- package/ui/Slider/Slider.js +50 -0
- package/ui/Slider/index.js +4 -0
- package/ui/Spinner/Spinner.js +21 -0
- package/ui/Spinner/index.js +5 -0
- package/ui/SpinnerSquare/SpinnerSquare.css +1 -0
- package/ui/SpinnerSquare/SpinnerSquare.js +22 -0
- package/ui/SpinnerSquare/index.js +4 -0
- package/ui/StatisticCard/StatisticCard.js +27 -0
- package/ui/StatisticCard/index.js +4 -0
- package/ui/StatisticCard/types.js +0 -0
- package/ui/Suggestions/Suggestions.js +244 -0
- package/ui/Suggestions/index.js +4 -0
- package/ui/Switch/Switch.js +64 -0
- package/ui/Switch/index.js +4 -0
- package/ui/SyncProcessBar/SyncProcessBar.js +14 -0
- package/ui/SyncProcessBar/index.js +4 -0
- package/ui/Table/GroupHeaderRow.js +36 -0
- package/ui/Table/RowGrouped.js +19 -0
- package/ui/Table/ServerGroupedTableBody.js +89 -0
- package/ui/Table/SortableHeader.js +46 -0
- package/ui/Table/Table.js +110 -0
- package/ui/Table/TableWrap.js +124 -0
- package/ui/Table/columnStyle.js +14 -0
- package/ui/Table/index.js +28 -0
- package/ui/Tabs/Tabs.js +76 -0
- package/ui/Tabs/index.js +4 -0
- package/ui/TextTruncate/TextTruncate.js +107 -0
- package/ui/TextTruncate/index.js +4 -0
- package/ui/Textarea/Textarea.js +20 -0
- package/ui/Textarea/index.js +4 -0
- package/ui/ThemeToggle/ThemeToggle.js +23 -0
- package/ui/ThemeToggle/index.js +4 -0
- package/ui/Toast/Toast.js +23 -0
- package/ui/Toast/index.js +4 -0
- package/ui/Tooltip/Tooltip.js +17 -0
- package/ui/Tooltip/TooltipLayout.js +60 -0
- package/ui/Tooltip/index.js +14 -0
- package/ui/TreeGuide/TreeGuide.js +23 -0
- package/ui/TreeGuide/index.js +5 -0
- package/ui/entries/charts.js +2 -0
- package/ui/entries/domain.js +3 -0
- package/ui/index.js +45 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDownIcon, Loader2 } from "lucide-react";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
5
|
+
import { Badge } from "../Badge/Badge.js";
|
|
6
|
+
import { Checkbox } from "../Checkbox/Checkbox.js";
|
|
7
|
+
import { SearchInput } from "../SearchInput/SearchInput.js";
|
|
8
|
+
import { ScrollArea } from "../ScrollArea/ScrollArea.js";
|
|
9
|
+
import { cn } from "../../lib/cn.js";
|
|
10
|
+
function MultiSelect({
|
|
11
|
+
loading = false,
|
|
12
|
+
options,
|
|
13
|
+
value = [],
|
|
14
|
+
placeholder = "Select elements...",
|
|
15
|
+
className,
|
|
16
|
+
disabled = false,
|
|
17
|
+
maxDisplay = 3,
|
|
18
|
+
maxSelection,
|
|
19
|
+
searchable = true,
|
|
20
|
+
size = "default",
|
|
21
|
+
dropdownClassName,
|
|
22
|
+
align = "start",
|
|
23
|
+
variant,
|
|
24
|
+
badgeClassNames,
|
|
25
|
+
id,
|
|
26
|
+
name,
|
|
27
|
+
onChange
|
|
28
|
+
}) {
|
|
29
|
+
const [open, setOpen] = useState(false);
|
|
30
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
31
|
+
const filteredOptions = useMemo(() => {
|
|
32
|
+
if (!searchQuery) return options;
|
|
33
|
+
const query = searchQuery.toLowerCase();
|
|
34
|
+
return options.filter((option) => option.label.toLowerCase().includes(query));
|
|
35
|
+
}, [options, searchQuery]);
|
|
36
|
+
const selectedOptions = useMemo(
|
|
37
|
+
() => options.filter((option) => value.includes(option.value)),
|
|
38
|
+
[options, value]
|
|
39
|
+
);
|
|
40
|
+
const displayedBadges = selectedOptions.slice(0, maxDisplay);
|
|
41
|
+
const remainingCount = selectedOptions.length - maxDisplay;
|
|
42
|
+
const isMaxReached = maxSelection !== void 0 && value.length >= maxSelection;
|
|
43
|
+
const handleToggle = (optionValue) => {
|
|
44
|
+
const isSelected = value.includes(optionValue);
|
|
45
|
+
if (isSelected) {
|
|
46
|
+
onChange(value.filter((v) => v !== optionValue));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (isMaxReached) return;
|
|
50
|
+
onChange([...value, optionValue]);
|
|
51
|
+
};
|
|
52
|
+
const handleRemove = (optionValue) => {
|
|
53
|
+
onChange(value.filter((v) => v !== optionValue));
|
|
54
|
+
};
|
|
55
|
+
const renderSelectedBadges = () => {
|
|
56
|
+
if (selectedOptions.length === 0) {
|
|
57
|
+
return /* @__PURE__ */ jsx("span", { className: "text-gray-chateau", children: placeholder });
|
|
58
|
+
}
|
|
59
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
60
|
+
displayedBadges.map((option) => /* @__PURE__ */ jsx(
|
|
61
|
+
Badge,
|
|
62
|
+
{
|
|
63
|
+
className: badgeClassNames,
|
|
64
|
+
variant: variant || option.badgeVariant,
|
|
65
|
+
onRemove: () => handleRemove(option.value),
|
|
66
|
+
children: option.label
|
|
67
|
+
},
|
|
68
|
+
option.value
|
|
69
|
+
)),
|
|
70
|
+
remainingCount > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "outline", children: [
|
|
71
|
+
"+",
|
|
72
|
+
remainingCount
|
|
73
|
+
] })
|
|
74
|
+
] });
|
|
75
|
+
};
|
|
76
|
+
const renderOptionItem = (option) => {
|
|
77
|
+
const isSelected = value.includes(option.value);
|
|
78
|
+
const isDisabled = option.disabled || !isSelected && isMaxReached;
|
|
79
|
+
return /* @__PURE__ */ jsxs(
|
|
80
|
+
"label",
|
|
81
|
+
{
|
|
82
|
+
className: cn(
|
|
83
|
+
"flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-xs transition-colors",
|
|
84
|
+
"hover:bg-hover focus:bg-hover focus:text-default",
|
|
85
|
+
isSelected && "bg-hover",
|
|
86
|
+
isDisabled && "cursor-not-allowed opacity-50"
|
|
87
|
+
),
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ jsx(
|
|
90
|
+
Checkbox,
|
|
91
|
+
{
|
|
92
|
+
checked: isSelected,
|
|
93
|
+
onCheckedChange: () => handleToggle(option.value),
|
|
94
|
+
disabled: isDisabled
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
/* @__PURE__ */ jsxs("span", { className: "flex flex-1 items-center gap-2", children: [
|
|
98
|
+
option.label,
|
|
99
|
+
option.typeLabel && /* @__PURE__ */ jsx(Badge, { variant: option.badgeVariant, className: "text-2xs", children: option.typeLabel })
|
|
100
|
+
] })
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
option.value
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
return /* @__PURE__ */ jsxs(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
107
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
108
|
+
"button",
|
|
109
|
+
{
|
|
110
|
+
type: "button",
|
|
111
|
+
id,
|
|
112
|
+
name,
|
|
113
|
+
disabled,
|
|
114
|
+
"data-size": size,
|
|
115
|
+
"data-state": open ? "open" : "closed",
|
|
116
|
+
className: cn(
|
|
117
|
+
'border-border bg-secondary data-[placeholder]:text-gray-chateau [&_svg:not([class*="text-"])]:text-gray-chateau flex min-h-9 w-full items-center justify-between gap-2 rounded-md border px-3 py-1 text-xs font-normal transition-[color,box-shadow] outline-none',
|
|
118
|
+
"focus-visible:border-success focus-visible:ring-success/40 focus-visible:ring-[2px]",
|
|
119
|
+
"data-[state=open]:border-success data-[state=open]:ring-success/40 data-[state=open]:ring-[2px]",
|
|
120
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
121
|
+
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
122
|
+
className
|
|
123
|
+
),
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-wrap items-center gap-1", children: renderSelectedBadges() }),
|
|
126
|
+
loading ? /* @__PURE__ */ jsx(Loader2, { className: "text-gray-chateau size-4 animate-spin" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "ml-2 size-4 shrink-0 opacity-50" })
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
) }),
|
|
130
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
131
|
+
PopoverPrimitive.Content,
|
|
132
|
+
{
|
|
133
|
+
align,
|
|
134
|
+
sideOffset: 4,
|
|
135
|
+
className: cn(
|
|
136
|
+
"bg-secondary border-border text-foreground z-50 rounded-md border shadow-md outline-none",
|
|
137
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
138
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
139
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
140
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
|
|
141
|
+
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
142
|
+
dropdownClassName
|
|
143
|
+
),
|
|
144
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 p-3", children: [
|
|
145
|
+
searchable && /* @__PURE__ */ jsx(
|
|
146
|
+
SearchInput,
|
|
147
|
+
{
|
|
148
|
+
className: "w-full text-xs",
|
|
149
|
+
classNamesInput: "h-10",
|
|
150
|
+
value: searchQuery,
|
|
151
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
152
|
+
placeholder: "Search..."
|
|
153
|
+
}
|
|
154
|
+
),
|
|
155
|
+
/* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx("div", { className: "flex max-h-64 flex-col gap-2", children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-gray-chateau py-6 text-center text-xs", children: "Nothing found" }) : filteredOptions.map(renderOptionItem) }) })
|
|
156
|
+
] })
|
|
157
|
+
}
|
|
158
|
+
) })
|
|
159
|
+
] });
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
MultiSelect
|
|
163
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowLeft } from "lucide-react";
|
|
3
|
+
import { Link } from "react-router-dom";
|
|
4
|
+
import { cn } from "../../lib/cn.js";
|
|
5
|
+
import { Button } from "../Button/Button.js";
|
|
6
|
+
import { ConditionalContent } from "../ConditionalContent/ConditionalContent.js";
|
|
7
|
+
import { Skeleton } from "../Skeleton/Skeleton.js";
|
|
8
|
+
const PageHeader = ({
|
|
9
|
+
loading,
|
|
10
|
+
title,
|
|
11
|
+
titleIcon,
|
|
12
|
+
backLink,
|
|
13
|
+
description,
|
|
14
|
+
descriptionSize = "md",
|
|
15
|
+
className,
|
|
16
|
+
titleClassName,
|
|
17
|
+
children
|
|
18
|
+
}) => {
|
|
19
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-6 max-lg:flex-wrap", className), children: [
|
|
20
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
21
|
+
backLink && /* @__PURE__ */ jsx(Link, { to: backLink, children: /* @__PURE__ */ jsx(Button, { variant: "icon", size: "xs", children: /* @__PURE__ */ jsx(ArrowLeft, { size: 20 }) }) }),
|
|
22
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-1", children: [
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
ConditionalContent,
|
|
25
|
+
{
|
|
26
|
+
loading: !!loading,
|
|
27
|
+
loadingContent: /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-64" }),
|
|
28
|
+
loadedContent: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
29
|
+
titleIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: titleIcon }),
|
|
30
|
+
/* @__PURE__ */ jsx("h2", { className: cn("text-default text-xl font-medium break-all", titleClassName), children: title })
|
|
31
|
+
] })
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
description && /* @__PURE__ */ jsx(
|
|
35
|
+
"div",
|
|
36
|
+
{
|
|
37
|
+
className: cn(
|
|
38
|
+
"text-gray-chateau break-all",
|
|
39
|
+
descriptionSize === "sm" ? "text-2xs" : "text-sm"
|
|
40
|
+
),
|
|
41
|
+
children: description
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
] })
|
|
45
|
+
] }),
|
|
46
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children })
|
|
47
|
+
] });
|
|
48
|
+
};
|
|
49
|
+
export {
|
|
50
|
+
PageHeader
|
|
51
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
|
4
|
+
function Pagination({ className, ...props }) {
|
|
5
|
+
return /* @__PURE__ */ jsx(
|
|
6
|
+
"nav",
|
|
7
|
+
{
|
|
8
|
+
role: "navigation",
|
|
9
|
+
"aria-label": "pagination",
|
|
10
|
+
"data-slot": "pagination",
|
|
11
|
+
className: cn("mx-auto flex w-full justify-center", className),
|
|
12
|
+
...props
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
function PaginationContent({ className, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
"ul",
|
|
19
|
+
{
|
|
20
|
+
"data-slot": "pagination-content",
|
|
21
|
+
className: cn("flex flex-row items-center gap-1", className),
|
|
22
|
+
...props
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function PaginationItem({ ...props }) {
|
|
27
|
+
return /* @__PURE__ */ jsx("li", { "data-slot": "pagination-item", ...props });
|
|
28
|
+
}
|
|
29
|
+
function PaginationLink({ className, isActive, ...props }) {
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
"a",
|
|
32
|
+
{
|
|
33
|
+
"aria-current": isActive ? "page" : void 0,
|
|
34
|
+
"data-slot": "pagination-link",
|
|
35
|
+
"data-active": isActive,
|
|
36
|
+
className: cn(
|
|
37
|
+
"hover:bg-hover flex items-center justify-center rounded-sm border border-transparent",
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
...props
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function PaginationPrevious({ className, ...props }) {
|
|
45
|
+
return /* @__PURE__ */ jsxs(
|
|
46
|
+
PaginationLink,
|
|
47
|
+
{
|
|
48
|
+
"aria-label": "Go to previous page",
|
|
49
|
+
size: "s",
|
|
50
|
+
className: cn("gap-1 px-2.5 sm:pl-2.5", className),
|
|
51
|
+
...props,
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx(ChevronLeftIcon, {}),
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:block", children: "Previous" })
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
function PaginationNext({ className, ...props }) {
|
|
60
|
+
return /* @__PURE__ */ jsxs(
|
|
61
|
+
PaginationLink,
|
|
62
|
+
{
|
|
63
|
+
"aria-label": "Go to next page",
|
|
64
|
+
size: "s",
|
|
65
|
+
className: cn("gap-1 px-2.5 sm:pr-2.5", className),
|
|
66
|
+
...props,
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:block", children: "Next" }),
|
|
69
|
+
/* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
function PaginationEllipsis({ className, ...props }) {
|
|
75
|
+
return /* @__PURE__ */ jsxs(
|
|
76
|
+
"span",
|
|
77
|
+
{
|
|
78
|
+
"aria-hidden": true,
|
|
79
|
+
"data-slot": "pagination-ellipsis",
|
|
80
|
+
className: cn("flex size-9 items-center justify-center", className),
|
|
81
|
+
...props,
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ jsx(MoreHorizontalIcon, { className: "size-4" }),
|
|
84
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "More pages" })
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
Pagination,
|
|
91
|
+
PaginationContent,
|
|
92
|
+
PaginationEllipsis,
|
|
93
|
+
PaginationItem,
|
|
94
|
+
PaginationLink,
|
|
95
|
+
PaginationNext,
|
|
96
|
+
PaginationPrevious
|
|
97
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { Button } from "../Button/Button.js";
|
|
4
|
+
import { Input } from "../Input/Input.js";
|
|
5
|
+
import { SelectDefault } from "../Select/SelectDefault.js";
|
|
6
|
+
import {
|
|
7
|
+
Pagination,
|
|
8
|
+
PaginationContent,
|
|
9
|
+
PaginationEllipsis,
|
|
10
|
+
PaginationItem,
|
|
11
|
+
PaginationLink,
|
|
12
|
+
PaginationNext,
|
|
13
|
+
PaginationPrevious
|
|
14
|
+
} from "./Pagination.js";
|
|
15
|
+
const perPageOptions = [
|
|
16
|
+
{ label: "10", value: "10" },
|
|
17
|
+
{ label: "25", value: "25" },
|
|
18
|
+
{ label: "50", value: "50" },
|
|
19
|
+
{ label: "100", value: "100" }
|
|
20
|
+
];
|
|
21
|
+
const PaginationWrap = ({
|
|
22
|
+
page,
|
|
23
|
+
totalPages,
|
|
24
|
+
limit = 25,
|
|
25
|
+
maxVisible = 5,
|
|
26
|
+
optionsPerPage,
|
|
27
|
+
onPageChange,
|
|
28
|
+
setLimit = () => {
|
|
29
|
+
}
|
|
30
|
+
}) => {
|
|
31
|
+
const [pageGo, setPageGo] = useState(null);
|
|
32
|
+
const pageNumbers = useMemo(() => {
|
|
33
|
+
const pages = [];
|
|
34
|
+
if (totalPages <= maxVisible) {
|
|
35
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
36
|
+
pages.push(i);
|
|
37
|
+
}
|
|
38
|
+
} else if (page <= 3) {
|
|
39
|
+
for (let i = 1; i <= 4; i++) {
|
|
40
|
+
pages.push(i);
|
|
41
|
+
}
|
|
42
|
+
pages.push(-1);
|
|
43
|
+
pages.push(totalPages);
|
|
44
|
+
} else if (page >= totalPages - 2) {
|
|
45
|
+
pages.push(1);
|
|
46
|
+
pages.push(-1);
|
|
47
|
+
for (let i = totalPages - 3; i <= totalPages; i++) {
|
|
48
|
+
pages.push(i);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
pages.push(1);
|
|
52
|
+
pages.push(-1);
|
|
53
|
+
for (let i = page - 1; i <= page + 1; i++) {
|
|
54
|
+
pages.push(i);
|
|
55
|
+
}
|
|
56
|
+
pages.push(-1);
|
|
57
|
+
pages.push(totalPages);
|
|
58
|
+
}
|
|
59
|
+
return pages;
|
|
60
|
+
}, [page, totalPages, maxVisible]);
|
|
61
|
+
const onPageGoClick = () => {
|
|
62
|
+
onPageChange(Number(pageGo));
|
|
63
|
+
setPageGo(null);
|
|
64
|
+
};
|
|
65
|
+
const limitItemChange = (value) => {
|
|
66
|
+
setLimit(Number(value));
|
|
67
|
+
setPageGo(null);
|
|
68
|
+
};
|
|
69
|
+
const previousPageClick = () => {
|
|
70
|
+
onPageChange(Math.max(1, page - 1));
|
|
71
|
+
setPageGo(null);
|
|
72
|
+
};
|
|
73
|
+
const nextPageClick = () => {
|
|
74
|
+
onPageChange(Math.min(totalPages, page + 1));
|
|
75
|
+
setPageGo(null);
|
|
76
|
+
};
|
|
77
|
+
const pageClick = (page2) => {
|
|
78
|
+
onPageChange(page2);
|
|
79
|
+
setPageGo(null);
|
|
80
|
+
};
|
|
81
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 xl:flex-nowrap", children: [
|
|
82
|
+
/* @__PURE__ */ jsxs("div", { className: "order-2 flex items-center gap-2 xl:order-1", children: [
|
|
83
|
+
/* @__PURE__ */ jsx("div", { className: "text-gray-chateau hidden text-xs whitespace-nowrap lg:flex", children: "Items per page:" }),
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
85
|
+
SelectDefault,
|
|
86
|
+
{
|
|
87
|
+
className: "h-8 text-xs",
|
|
88
|
+
options: optionsPerPage || perPageOptions,
|
|
89
|
+
value: limit.toString(),
|
|
90
|
+
placeholder: "Select items per page",
|
|
91
|
+
onChange: limitItemChange
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
] }),
|
|
95
|
+
/* @__PURE__ */ jsx(Pagination, { className: "order-1 xl:order-2", children: /* @__PURE__ */ jsxs(PaginationContent, { children: [
|
|
96
|
+
/* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(
|
|
97
|
+
PaginationPrevious,
|
|
98
|
+
{
|
|
99
|
+
onClick: previousPageClick,
|
|
100
|
+
className: `h-8 text-xs ${page === 1 ? "pointer-events-none opacity-50" : "cursor-pointer"}`
|
|
101
|
+
}
|
|
102
|
+
) }),
|
|
103
|
+
pageNumbers.map((pageNum, idx) => /* @__PURE__ */ jsx(PaginationItem, { children: pageNum === -1 ? /* @__PURE__ */ jsx(PaginationEllipsis, {}) : /* @__PURE__ */ jsx(
|
|
104
|
+
PaginationLink,
|
|
105
|
+
{
|
|
106
|
+
className: `h-8 w-8 cursor-pointer text-xs ${page === pageNum ? "border-border" : ""}`,
|
|
107
|
+
onClick: () => pageClick(pageNum),
|
|
108
|
+
isActive: page === pageNum,
|
|
109
|
+
children: pageNum
|
|
110
|
+
}
|
|
111
|
+
) }, idx)),
|
|
112
|
+
/* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(
|
|
113
|
+
PaginationNext,
|
|
114
|
+
{
|
|
115
|
+
onClick: nextPageClick,
|
|
116
|
+
className: `h-8 text-xs ${page === totalPages || totalPages === 0 ? "pointer-events-none opacity-50" : "cursor-pointer"}`
|
|
117
|
+
}
|
|
118
|
+
) })
|
|
119
|
+
] }) }),
|
|
120
|
+
/* @__PURE__ */ jsxs("div", { className: "order-3 flex items-center gap-3 xl:order-2", children: [
|
|
121
|
+
/* @__PURE__ */ jsx("div", { className: "text-gray-chateau hidden text-xs whitespace-nowrap lg:flex", children: "Go to:" }),
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
Input,
|
|
124
|
+
{
|
|
125
|
+
className: "h-8 w-13 px-2 text-xs",
|
|
126
|
+
type: "text",
|
|
127
|
+
value: pageGo ?? "",
|
|
128
|
+
placeholder: "Page",
|
|
129
|
+
pattern: "^[0-9]*$",
|
|
130
|
+
onChange: (e) => setPageGo(Number(e.target.value) || null)
|
|
131
|
+
}
|
|
132
|
+
),
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
Button,
|
|
135
|
+
{
|
|
136
|
+
className: "px-2 text-xs",
|
|
137
|
+
size: "s",
|
|
138
|
+
variant: "secondary",
|
|
139
|
+
disabled: pageGo !== null ? !(pageGo > 0 && pageGo <= totalPages) : true,
|
|
140
|
+
onClick: onPageGoClick,
|
|
141
|
+
children: "Go"
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
] })
|
|
145
|
+
] });
|
|
146
|
+
};
|
|
147
|
+
export {
|
|
148
|
+
PaginationWrap
|
|
149
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Pagination as Pagination2,
|
|
3
|
+
PaginationContent as PaginationContent2,
|
|
4
|
+
PaginationEllipsis as PaginationEllipsis2,
|
|
5
|
+
PaginationItem as PaginationItem2,
|
|
6
|
+
PaginationLink,
|
|
7
|
+
PaginationNext as PaginationNext2,
|
|
8
|
+
PaginationPrevious as PaginationPrevious2
|
|
9
|
+
} from "./Pagination.js";
|
|
10
|
+
import { PaginationWrap } from "./PaginationWrap.js";
|
|
11
|
+
export {
|
|
12
|
+
Pagination2 as Pagination,
|
|
13
|
+
PaginationContent2 as PaginationContent,
|
|
14
|
+
PaginationEllipsis2 as PaginationEllipsis,
|
|
15
|
+
PaginationItem2 as PaginationItem,
|
|
16
|
+
PaginationLink,
|
|
17
|
+
PaginationNext2 as PaginationNext,
|
|
18
|
+
PaginationPrevious2 as PaginationPrevious,
|
|
19
|
+
PaginationWrap
|
|
20
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
Indicator as RadioGroupIndicatorPrimitive,
|
|
4
|
+
Item as RadioGroupItemPrimitive,
|
|
5
|
+
Root as RadioGroupPrimitive
|
|
6
|
+
} from "@radix-ui/react-radio-group";
|
|
7
|
+
import { cn } from "../../lib/cn.js";
|
|
8
|
+
function RadioGroup({ className, ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(
|
|
10
|
+
RadioGroupPrimitive,
|
|
11
|
+
{
|
|
12
|
+
"data-slot": "radio-group",
|
|
13
|
+
className: cn("grid w-full gap-2", className),
|
|
14
|
+
...props
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
function RadioGroupItem({
|
|
19
|
+
className,
|
|
20
|
+
...props
|
|
21
|
+
}) {
|
|
22
|
+
return /* @__PURE__ */ jsx(
|
|
23
|
+
RadioGroupItemPrimitive,
|
|
24
|
+
{
|
|
25
|
+
"data-slot": "radio-group-item",
|
|
26
|
+
className: cn(
|
|
27
|
+
"group/radio-group-item peer border-border bg-secondary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-critical aria-invalid:ring-critical/20 aria-invalid:data-[state=checked]:border-success dark:bg-secondary/30 dark:aria-invalid:border-critical/50 dark:aria-invalid:ring-critical/40 data-[state=checked]:border-success data-[state=checked]:bg-success data-[state=checked]:text-foreground dark:data-[state=checked]:bg-secondary relative flex aspect-square size-4 shrink-0 rounded-full border outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-[3px]",
|
|
28
|
+
className
|
|
29
|
+
),
|
|
30
|
+
...props,
|
|
31
|
+
children: /* @__PURE__ */ jsx(
|
|
32
|
+
RadioGroupIndicatorPrimitive,
|
|
33
|
+
{
|
|
34
|
+
"data-slot": "radio-group-indicator",
|
|
35
|
+
className: "flex size-4 items-center justify-center",
|
|
36
|
+
children: /* @__PURE__ */ jsx("span", { className: "bg-success absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full" })
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
RadioGroup,
|
|
44
|
+
RadioGroupItem
|
|
45
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
|
3
|
+
import { cn } from "../../lib/cn.js";
|
|
4
|
+
function ScrollArea({ className, children, orientation = "vertical", ...props }) {
|
|
5
|
+
return /* @__PURE__ */ jsxs(
|
|
6
|
+
ScrollAreaPrimitive.Root,
|
|
7
|
+
{
|
|
8
|
+
"data-slot": "scroll-area",
|
|
9
|
+
className: cn("relative flex min-h-0 flex-col overflow-hidden", className),
|
|
10
|
+
...props,
|
|
11
|
+
children: [
|
|
12
|
+
/* @__PURE__ */ jsx(
|
|
13
|
+
ScrollAreaPrimitive.Viewport,
|
|
14
|
+
{
|
|
15
|
+
"data-slot": "scroll-area-viewport",
|
|
16
|
+
className: "focus-visible:ring-ring/50 h-0 min-h-0 w-full flex-1 rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&>div]:!block",
|
|
17
|
+
children
|
|
18
|
+
}
|
|
19
|
+
),
|
|
20
|
+
(orientation === "vertical" || orientation === "both") && /* @__PURE__ */ jsx(ScrollBar, { orientation: "vertical" }),
|
|
21
|
+
(orientation === "horizontal" || orientation === "both") && /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" }),
|
|
22
|
+
/* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function ScrollBar({
|
|
28
|
+
className,
|
|
29
|
+
orientation = "vertical",
|
|
30
|
+
...props
|
|
31
|
+
}) {
|
|
32
|
+
return /* @__PURE__ */ jsx(
|
|
33
|
+
ScrollAreaPrimitive.ScrollAreaScrollbar,
|
|
34
|
+
{
|
|
35
|
+
"data-slot": "scroll-area-scrollbar",
|
|
36
|
+
orientation,
|
|
37
|
+
className: cn(
|
|
38
|
+
"flex touch-none p-px transition-colors select-none",
|
|
39
|
+
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
|
|
40
|
+
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
|
|
41
|
+
className
|
|
42
|
+
),
|
|
43
|
+
...props,
|
|
44
|
+
children: /* @__PURE__ */ jsx(
|
|
45
|
+
ScrollAreaPrimitive.ScrollAreaThumb,
|
|
46
|
+
{
|
|
47
|
+
"data-slot": "scroll-area-thumb",
|
|
48
|
+
className: "bg-border relative flex-1 rounded-full"
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
ScrollArea,
|
|
56
|
+
ScrollBar
|
|
57
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/cn.js";
|
|
3
|
+
import { SearchIcon, XIcon } from "lucide-react";
|
|
4
|
+
import { Input } from "../Input/Input.js";
|
|
5
|
+
const SearchInput = ({
|
|
6
|
+
className,
|
|
7
|
+
classNamesInput,
|
|
8
|
+
value,
|
|
9
|
+
placeholder,
|
|
10
|
+
onChange,
|
|
11
|
+
...props
|
|
12
|
+
}) => {
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
|
|
14
|
+
/* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute top-1/2 left-2 flex size-4 -translate-y-[60%] items-center", children: /* @__PURE__ */ jsx(SearchIcon, { className: "text-subdued h-4 w-4" }) }),
|
|
15
|
+
/* @__PURE__ */ jsx(
|
|
16
|
+
Input,
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
className: cn("px-7", classNamesInput),
|
|
20
|
+
placeholder: placeholder || "Search...",
|
|
21
|
+
...props,
|
|
22
|
+
value,
|
|
23
|
+
onChange
|
|
24
|
+
}
|
|
25
|
+
),
|
|
26
|
+
value && /* @__PURE__ */ jsx(
|
|
27
|
+
"button",
|
|
28
|
+
{
|
|
29
|
+
className: "absolute inset-y-0 right-2 flex cursor-pointer items-center",
|
|
30
|
+
onClick: () => onChange?.({ target: { value: "" } }),
|
|
31
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "text-subdued hover:text-foreground h-4 w-4" })
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
] });
|
|
35
|
+
};
|
|
36
|
+
export {
|
|
37
|
+
SearchInput
|
|
38
|
+
};
|