@meta-1/design 0.0.199 → 0.0.201
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/package.json +3 -1
- package/src/assets/locales/en-us.ts +4 -0
- package/src/assets/locales/zh-cn.ts +4 -0
- package/src/assets/locales/zh-tw.ts +4 -0
- package/src/assets/style/theme.css +72 -21
- package/src/components/ui/button.tsx +28 -18
- package/src/components/uix/action/index.tsx +7 -5
- package/src/components/uix/action/style.css +21 -0
- package/src/components/uix/alert/index.tsx +5 -5
- package/src/components/uix/alert-dialog/index.tsx +56 -16
- package/src/components/uix/badge/index.tsx +8 -2
- package/src/components/uix/button/index.tsx +7 -5
- package/src/components/uix/card/index.tsx +7 -4
- package/src/components/uix/checkbox-group/index.tsx +3 -4
- package/src/components/uix/combo-select/index.tsx +99 -129
- package/src/components/uix/command/index.tsx +126 -0
- package/src/components/uix/data-grid/index.tsx +625 -0
- package/src/components/uix/data-grid/overlays.tsx +26 -0
- package/src/components/uix/data-grid/style.css +6 -0
- package/src/components/uix/data-table/index.tsx +10 -7
- package/src/components/uix/date-picker/index.tsx +55 -46
- package/src/components/uix/date-range-picker/index.tsx +116 -36
- package/src/components/uix/dialog/index.tsx +5 -5
- package/src/components/uix/dropdown/index.tsx +1 -1
- package/src/components/uix/input/index.tsx +23 -0
- package/src/components/uix/message/index.tsx +4 -4
- package/src/components/uix/pagination/index.tsx +17 -31
- package/src/components/uix/popover/index.tsx +30 -0
- package/src/components/uix/radio-group/index.tsx +2 -2
- package/src/components/uix/select/index.tsx +6 -2
- package/src/components/uix/sheet/index.tsx +76 -0
- package/src/components/uix/tabs/index.tsx +38 -0
- package/src/components/uix/tags-input/index.tsx +22 -3
- package/src/components/uix/textarea/index.tsx +23 -0
- package/src/components/uix/tooltip/index.tsx +5 -4
- package/src/components/uix/tree/style.css +1 -0
- package/src/components/uix/tree-select/index.tsx +59 -64
- package/src/components/uix/uploader/index.tsx +1 -1
- package/src/components/uix/value-formatter/index.tsx +40 -46
- package/src/index.ts +19 -36
- package/src/lib/utils.ts +50 -1
- package/src/components/uix/breadcrumbs/index.tsx +0 -38
- package/src/components/uix/space/index.tsx +0 -24
|
@@ -23,10 +23,12 @@ import {
|
|
|
23
23
|
type DropdownMenuItemProps,
|
|
24
24
|
Filters,
|
|
25
25
|
type FiltersProps,
|
|
26
|
+
type Formatters,
|
|
26
27
|
generateColumnStorageKey,
|
|
27
28
|
Pagination,
|
|
28
29
|
type PaginationProps,
|
|
29
30
|
Spin,
|
|
31
|
+
ValueFormatter,
|
|
30
32
|
} from "@meta-1/design";
|
|
31
33
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../ui/table";
|
|
32
34
|
import "./style.css";
|
|
@@ -36,7 +38,6 @@ import classNames from "classnames";
|
|
|
36
38
|
import get from "lodash/get";
|
|
37
39
|
|
|
38
40
|
import { UIXContext } from "@meta-1/design/components/uix/config-provider";
|
|
39
|
-
import { type Formatters, type FunctionMap, formatValue } from "@meta-1/design/components/uix/value-formatter";
|
|
40
41
|
|
|
41
42
|
export interface StickyColumnProps {
|
|
42
43
|
key: string;
|
|
@@ -63,7 +64,6 @@ export interface DataTableProps<TData> {
|
|
|
63
64
|
load?: (params?: unknown) => Promise<unknown> | unknown;
|
|
64
65
|
filter?: FiltersProps;
|
|
65
66
|
pagination?: PaginationProps | boolean;
|
|
66
|
-
cellHandles?: FunctionMap;
|
|
67
67
|
empty?: string;
|
|
68
68
|
showHeader?: boolean;
|
|
69
69
|
onRowClick?: (row: Row<TData>) => void;
|
|
@@ -170,7 +170,6 @@ export function DataTable<TData>(props: DataTableProps<TData>) {
|
|
|
170
170
|
loading,
|
|
171
171
|
pagination,
|
|
172
172
|
load,
|
|
173
|
-
cellHandles,
|
|
174
173
|
showHeader = true,
|
|
175
174
|
inCard = false,
|
|
176
175
|
maxHeight,
|
|
@@ -429,10 +428,14 @@ export function DataTable<TData>(props: DataTableProps<TData>) {
|
|
|
429
428
|
const render = ctx.renderValue;
|
|
430
429
|
// biome-ignore lint/suspicious/noExplicitAny: <formatters>
|
|
431
430
|
const formatters = (cell.column.columnDef as any).formatters || [];
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const content =
|
|
431
|
+
const hasFormatters = formatters.length > 0;
|
|
432
|
+
// biome-ignore lint/suspicious/noExplicitAny: <cellValue can be any type>
|
|
433
|
+
const cellValue: any = render();
|
|
434
|
+
const content = hasFormatters ? (
|
|
435
|
+
<ValueFormatter formatters={formatters} value={cellValue} />
|
|
436
|
+
) : (
|
|
437
|
+
flexRender(cell.column.columnDef.cell, ctx)
|
|
438
|
+
);
|
|
436
439
|
return (
|
|
437
440
|
<TableCell
|
|
438
441
|
className={cn(
|
|
@@ -4,7 +4,7 @@ import { addDays, format } from "date-fns";
|
|
|
4
4
|
import get from "lodash/get";
|
|
5
5
|
import { Calendar as CalendarIcon } from "lucide-react";
|
|
6
6
|
|
|
7
|
-
import { Button, Calendar, cn, Popover,
|
|
7
|
+
import { Button, Calendar, cn, Popover, Select } from "@meta-1/design";
|
|
8
8
|
import { UIXContext } from "@meta-1/design/components/uix/config-provider";
|
|
9
9
|
|
|
10
10
|
export type DatePickerProps = {
|
|
@@ -118,53 +118,62 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>((props, _r
|
|
|
118
118
|
|
|
119
119
|
const calendar = <Calendar locale={locale} mode="single" onSelect={handleSelect} selected={selectedDate} />;
|
|
120
120
|
|
|
121
|
+
const content = (
|
|
122
|
+
<>
|
|
123
|
+
{preset ? (
|
|
124
|
+
<>
|
|
125
|
+
<Select
|
|
126
|
+
className="w-full"
|
|
127
|
+
onChange={handlePresetChange}
|
|
128
|
+
options={options || []}
|
|
129
|
+
placeholder="请选择"
|
|
130
|
+
value={presetValue}
|
|
131
|
+
/>
|
|
132
|
+
<div className="rounded-md border">{calendar}</div>
|
|
133
|
+
</>
|
|
134
|
+
) : (
|
|
135
|
+
calendar
|
|
136
|
+
)}
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
|
|
121
140
|
return (
|
|
122
|
-
<Popover
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<span
|
|
137
|
-
aria-label="Clear date"
|
|
138
|
-
className="hidden cursor-pointer items-center justify-center group-hover:flex"
|
|
139
|
-
onClick={handleClear}
|
|
140
|
-
onPointerDown={(pointerEvent) => {
|
|
141
|
-
pointerEvent.preventDefault();
|
|
142
|
-
pointerEvent.stopPropagation();
|
|
143
|
-
}}
|
|
144
|
-
role="button"
|
|
145
|
-
tabIndex={-1}
|
|
146
|
-
>
|
|
147
|
-
<Cross2Icon />
|
|
148
|
-
</span>
|
|
149
|
-
) : null}
|
|
150
|
-
</Button>
|
|
151
|
-
</PopoverTrigger>
|
|
152
|
-
<PopoverContent align="start" className={cn("flex w-fit", preset ? "flex-col space-y-2 p-2" : "p-0")}>
|
|
153
|
-
{preset ? (
|
|
154
|
-
<>
|
|
155
|
-
<Select
|
|
156
|
-
className="w-full"
|
|
157
|
-
onChange={handlePresetChange}
|
|
158
|
-
options={options || []}
|
|
159
|
-
placeholder="请选择"
|
|
160
|
-
value={presetValue}
|
|
161
|
-
/>
|
|
162
|
-
<div className="rounded-md border">{calendar}</div>
|
|
163
|
-
</>
|
|
164
|
-
) : (
|
|
165
|
-
calendar
|
|
141
|
+
<Popover
|
|
142
|
+
align="start"
|
|
143
|
+
asChild
|
|
144
|
+
className={cn("flex w-fit", preset ? "flex-col gap-calendar p-calendar" : "p-0")}
|
|
145
|
+
content={content}
|
|
146
|
+
disabled={disabled}
|
|
147
|
+
onOpenChange={handleOpenChange}
|
|
148
|
+
open={popoverOpen}
|
|
149
|
+
>
|
|
150
|
+
<Button
|
|
151
|
+
className={cn(
|
|
152
|
+
"group min-h-8 w-full justify-start gap-1 p-select text-left font-normal",
|
|
153
|
+
!selectedDate && "text-muted-foreground",
|
|
154
|
+
className,
|
|
166
155
|
)}
|
|
167
|
-
|
|
156
|
+
disabled={disabled}
|
|
157
|
+
variant="outline"
|
|
158
|
+
>
|
|
159
|
+
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
160
|
+
<span className="flex-1">{selectedDate ? format(selectedDate, formatConfig) : placeholder}</span>
|
|
161
|
+
{allowClear && selectedDate && !disabled ? (
|
|
162
|
+
<span
|
|
163
|
+
aria-label="Clear date"
|
|
164
|
+
className="hidden cursor-pointer items-center justify-center group-hover:flex"
|
|
165
|
+
onClick={handleClear}
|
|
166
|
+
onPointerDown={(pointerEvent) => {
|
|
167
|
+
pointerEvent.preventDefault();
|
|
168
|
+
pointerEvent.stopPropagation();
|
|
169
|
+
}}
|
|
170
|
+
role="button"
|
|
171
|
+
tabIndex={-1}
|
|
172
|
+
>
|
|
173
|
+
<Cross2Icon />
|
|
174
|
+
</span>
|
|
175
|
+
) : null}
|
|
176
|
+
</Button>
|
|
168
177
|
</Popover>
|
|
169
178
|
);
|
|
170
179
|
});
|
|
@@ -1,68 +1,148 @@
|
|
|
1
|
-
import { forwardRef, type HTMLAttributes, useContext, useState } from "react";
|
|
1
|
+
import { forwardRef, type HTMLAttributes, type MouseEvent, useContext, useEffect, useState } from "react";
|
|
2
|
+
import { Cross2Icon } from "@radix-ui/react-icons";
|
|
2
3
|
import { format } from "date-fns";
|
|
3
4
|
import get from "lodash/get";
|
|
4
5
|
import { Calendar as CalendarIcon } from "lucide-react";
|
|
5
6
|
import type { DateRange } from "react-day-picker";
|
|
6
7
|
|
|
7
|
-
import { Button, Calendar, Popover
|
|
8
|
+
import { Button, Calendar, Popover } from "@meta-1/design";
|
|
8
9
|
import { UIXContext } from "@meta-1/design/components/uix/config-provider";
|
|
9
10
|
import { cn } from "@meta-1/design/lib";
|
|
10
11
|
|
|
12
|
+
export type { DateRange } from "react-day-picker";
|
|
13
|
+
|
|
11
14
|
export type DateRangePickerProps = {
|
|
12
15
|
value?: DateRange;
|
|
13
|
-
onChange?: (value: DateRange) => void;
|
|
16
|
+
onChange?: (value: DateRange | undefined) => void;
|
|
14
17
|
placeholder?: string;
|
|
15
18
|
format?: string;
|
|
16
|
-
|
|
19
|
+
allowClear?: boolean;
|
|
20
|
+
open?: boolean;
|
|
21
|
+
onOpenChange?: (open: boolean) => void;
|
|
22
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "onChange">;
|
|
17
23
|
|
|
18
24
|
export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>((props, forwardedRef) => {
|
|
19
|
-
const { className, value, onChange } = props;
|
|
25
|
+
const { className, value, onChange, allowClear = false, open, onOpenChange } = props;
|
|
20
26
|
const elementRef = forwardedRef;
|
|
21
27
|
|
|
28
|
+
const hasValueProp = Object.hasOwn(props, "value");
|
|
29
|
+
const isValueControlled = hasValueProp;
|
|
30
|
+
const hasOpenProp = Object.hasOwn(props, "open");
|
|
31
|
+
const isOpenControlled = hasOpenProp;
|
|
32
|
+
const [internalDate, setInternalDate] = useState<DateRange | undefined>(value);
|
|
33
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (isValueControlled) {
|
|
37
|
+
setInternalDate(value);
|
|
38
|
+
}
|
|
39
|
+
}, [isValueControlled, value]);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (isOpenControlled) {
|
|
43
|
+
setInternalOpen(Boolean(open));
|
|
44
|
+
}
|
|
45
|
+
}, [isOpenControlled, open]);
|
|
46
|
+
|
|
22
47
|
const config = useContext(UIXContext);
|
|
23
48
|
const locale = get(config.locale, "DateRangePicker.locale");
|
|
24
49
|
const formatConfig = props.format || get(config.locale, "DateRangePicker.format") || "yyyy-MM-dd";
|
|
25
50
|
|
|
26
|
-
const
|
|
51
|
+
const selectedDate = isValueControlled ? value : internalDate;
|
|
52
|
+
const popoverOpen = isOpenControlled ? open : internalOpen;
|
|
53
|
+
|
|
54
|
+
const closePopover = () => {
|
|
55
|
+
if (!isOpenControlled) {
|
|
56
|
+
setInternalOpen(false);
|
|
57
|
+
}
|
|
58
|
+
onOpenChange?.(false);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const handleOpenChange = (nextOpen: boolean) => {
|
|
62
|
+
onOpenChange?.(nextOpen);
|
|
63
|
+
if (!isOpenControlled) {
|
|
64
|
+
setInternalOpen(nextOpen);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handleClear = (event: MouseEvent<SVGSVGElement | HTMLSpanElement>) => {
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
event.stopPropagation();
|
|
71
|
+
if (!isValueControlled) {
|
|
72
|
+
setInternalDate(undefined);
|
|
73
|
+
}
|
|
74
|
+
onChange?.(undefined);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const content = (
|
|
78
|
+
<Calendar
|
|
79
|
+
defaultMonth={selectedDate?.from}
|
|
80
|
+
initialFocus
|
|
81
|
+
locale={locale}
|
|
82
|
+
mode="range"
|
|
83
|
+
numberOfMonths={2}
|
|
84
|
+
onSelect={(v) => {
|
|
85
|
+
if (!isValueControlled) {
|
|
86
|
+
setInternalDate(v);
|
|
87
|
+
}
|
|
88
|
+
onChange?.(v);
|
|
89
|
+
if (v?.to) {
|
|
90
|
+
closePopover();
|
|
91
|
+
}
|
|
92
|
+
}}
|
|
93
|
+
selected={selectedDate}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
27
96
|
|
|
28
97
|
return (
|
|
29
98
|
<div className={cn("grid gap-2", className)} ref={elementRef}>
|
|
30
|
-
<Popover
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
99
|
+
<Popover
|
|
100
|
+
align="start"
|
|
101
|
+
asChild
|
|
102
|
+
className="w-auto p-0"
|
|
103
|
+
content={content}
|
|
104
|
+
onOpenChange={handleOpenChange}
|
|
105
|
+
open={popoverOpen}
|
|
106
|
+
>
|
|
107
|
+
<Button
|
|
108
|
+
className={cn(
|
|
109
|
+
"group min-h-8 justify-start gap-1 p-select text-left font-normal",
|
|
110
|
+
!selectedDate && "text-muted-foreground",
|
|
111
|
+
)}
|
|
112
|
+
id="date"
|
|
113
|
+
type="button"
|
|
114
|
+
variant="outline"
|
|
115
|
+
>
|
|
116
|
+
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
117
|
+
<span className="flex-1">
|
|
118
|
+
{selectedDate?.from ? (
|
|
119
|
+
selectedDate.to ? (
|
|
41
120
|
<>
|
|
42
|
-
{format(
|
|
121
|
+
{format(selectedDate.from, formatConfig)} - {format(selectedDate.to, formatConfig)}
|
|
43
122
|
</>
|
|
44
123
|
) : (
|
|
45
|
-
format(
|
|
124
|
+
format(selectedDate.from, formatConfig)
|
|
46
125
|
)
|
|
47
126
|
) : (
|
|
48
|
-
|
|
127
|
+
props.placeholder
|
|
49
128
|
)}
|
|
50
|
-
</
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
129
|
+
</span>
|
|
130
|
+
{allowClear && selectedDate?.from ? (
|
|
131
|
+
<span
|
|
132
|
+
aria-label="Clear date range"
|
|
133
|
+
className="hidden cursor-pointer items-center justify-center group-hover:flex"
|
|
134
|
+
onClick={handleClear}
|
|
135
|
+
onPointerDown={(pointerEvent) => {
|
|
136
|
+
pointerEvent.preventDefault();
|
|
137
|
+
pointerEvent.stopPropagation();
|
|
138
|
+
}}
|
|
139
|
+
role="button"
|
|
140
|
+
tabIndex={-1}
|
|
141
|
+
>
|
|
142
|
+
<Cross2Icon />
|
|
143
|
+
</span>
|
|
144
|
+
) : null}
|
|
145
|
+
</Button>
|
|
66
146
|
</Popover>
|
|
67
147
|
</div>
|
|
68
148
|
);
|
|
@@ -49,22 +49,22 @@ export const Dialog: FC<DialogProps> = (props) => {
|
|
|
49
49
|
<DialogContent
|
|
50
50
|
aria-describedby={undefined}
|
|
51
51
|
autoFocus={false}
|
|
52
|
-
className={cn(className)}
|
|
52
|
+
className={cn("gap-dialog rounded-dialog", className)}
|
|
53
53
|
onClick={(e) => e.stopPropagation()}
|
|
54
54
|
onCloseClick={onCancel}
|
|
55
55
|
onOverlayClick={maskClosable ? onCancel : () => {}}
|
|
56
56
|
showClose={closable}
|
|
57
57
|
>
|
|
58
|
-
<DialogHeader className={cn(!title && !description && "sr-only")}>
|
|
59
|
-
<DialogTitle className={cn(!title && "sr-only")}>{title || "Dialog"}</DialogTitle>
|
|
58
|
+
<DialogHeader className={cn("p-dialog pb-0", !title && !description && "sr-only")}>
|
|
59
|
+
<DialogTitle className={cn("leading-normal", !title && "sr-only")}>{title || "Dialog"}</DialogTitle>
|
|
60
60
|
{description ? <DialogDescription>{description}</DialogDescription> : null}
|
|
61
61
|
</DialogHeader>
|
|
62
62
|
<div className="min-h-0 flex-1 overflow-auto">
|
|
63
|
-
<div className={cn("px-
|
|
63
|
+
<div className={cn("px-dialog", fitContent && "w-full min-w-fit", !footer && "pb-dialog", contentClassName)}>
|
|
64
64
|
{props.children}
|
|
65
65
|
</div>
|
|
66
66
|
</div>
|
|
67
|
-
{footer ? <DialogFooter>{footer}</DialogFooter> : null}
|
|
67
|
+
{footer ? <DialogFooter className="p-dialog pt-0">{footer}</DialogFooter> : null}
|
|
68
68
|
{loading ? (
|
|
69
69
|
<div
|
|
70
70
|
className={cn(
|
|
@@ -109,7 +109,7 @@ export const Dropdown: FC<DropdownProps> = (props) => {
|
|
|
109
109
|
return (
|
|
110
110
|
<DropdownMenu modal={modal} onOpenChange={props.onOpenChange} open={open}>
|
|
111
111
|
<DropdownMenuTrigger asChild={asChild}>{props.children}</DropdownMenuTrigger>
|
|
112
|
-
<DropdownMenuContent align={align} className={cn(props.className)} side={side}>
|
|
112
|
+
<DropdownMenuContent align={align} className={cn("rounded-popover p-popover", props.className)} side={side}>
|
|
113
113
|
{items.filter((item) => !item.hidden).map((child) => renderItem(child, { onItemClick, onCheckedChange }))}
|
|
114
114
|
</DropdownMenuContent>
|
|
115
115
|
</DropdownMenu>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
|
|
4
|
+
import { Input as UIInput } from "@meta-1/design/components/ui/input";
|
|
5
|
+
import { cn } from "@meta-1/design/lib";
|
|
6
|
+
|
|
7
|
+
export type InputProps = Omit<ComponentProps<typeof UIInput>, "size" | "onChange"> & {
|
|
8
|
+
onChange?: (value: string) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
|
|
12
|
+
const { className, onChange, ...rest } = props;
|
|
13
|
+
return (
|
|
14
|
+
<UIInput
|
|
15
|
+
{...rest}
|
|
16
|
+
className={cn("h-input rounded-input px-input", className)}
|
|
17
|
+
onChange={(e) => onChange?.(e.target.value)}
|
|
18
|
+
ref={ref}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
Input.displayName = "Input";
|
|
@@ -9,7 +9,7 @@ export const useMessage = () => {
|
|
|
9
9
|
unstyled: true,
|
|
10
10
|
...options,
|
|
11
11
|
className:
|
|
12
|
-
"group w-full max-w-sm border-success-foreground/20 bg-success/80 text-success-foreground rounded-
|
|
12
|
+
"group w-full max-w-sm border-success-foreground/20 bg-success/80 text-success-foreground rounded-message border p-message shadow-lg flex items-start gap-3 backdrop-blur-sm overflow-hidden",
|
|
13
13
|
descriptionClassName: "text-sm truncate",
|
|
14
14
|
});
|
|
15
15
|
},
|
|
@@ -18,7 +18,7 @@ export const useMessage = () => {
|
|
|
18
18
|
unstyled: true,
|
|
19
19
|
...options,
|
|
20
20
|
className:
|
|
21
|
-
"group w-full max-w-sm border-error-foreground/20 bg-error/80 text-error-foreground rounded-
|
|
21
|
+
"group w-full max-w-sm border-error-foreground/20 bg-error/80 text-error-foreground rounded-message border p-message shadow-lg flex items-start gap-3 backdrop-blur-sm overflow-hidden",
|
|
22
22
|
descriptionClassName: "text-sm truncate",
|
|
23
23
|
});
|
|
24
24
|
},
|
|
@@ -27,7 +27,7 @@ export const useMessage = () => {
|
|
|
27
27
|
unstyled: true,
|
|
28
28
|
...options,
|
|
29
29
|
className:
|
|
30
|
-
"group w-full max-w-sm border-warning-foreground/20 bg-warning/80 text-warning-foreground rounded-
|
|
30
|
+
"group w-full max-w-sm border-warning-foreground/20 bg-warning/80 text-warning-foreground rounded-message border p-message shadow-lg flex items-start gap-3 backdrop-blur-sm overflow-hidden",
|
|
31
31
|
descriptionClassName: "text-sm truncate",
|
|
32
32
|
});
|
|
33
33
|
},
|
|
@@ -36,7 +36,7 @@ export const useMessage = () => {
|
|
|
36
36
|
unstyled: true,
|
|
37
37
|
...options,
|
|
38
38
|
className:
|
|
39
|
-
"group w-full max-w-sm border-info-foreground/20 bg-info/80 text-info-foreground rounded-
|
|
39
|
+
"group w-full max-w-sm border-info-foreground/20 bg-info/80 text-info-foreground rounded-message border p-message shadow-lg flex items-start gap-3 backdrop-blur-sm overflow-hidden",
|
|
40
40
|
descriptionClassName: "text-sm truncate",
|
|
41
41
|
});
|
|
42
42
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type FC, useRef, useState } from "react";
|
|
2
2
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
3
3
|
|
|
4
|
-
import { Button } from "@meta-1/design/components/
|
|
5
|
-
import { Input } from "@meta-1/design/components/
|
|
6
|
-
import { Tabs
|
|
4
|
+
import { Button } from "@meta-1/design/components/uix/button";
|
|
5
|
+
import { Input } from "@meta-1/design/components/uix/input";
|
|
6
|
+
import { Tabs } from "@meta-1/design/components/uix/tabs";
|
|
7
7
|
|
|
8
8
|
export interface PaginationProps {
|
|
9
9
|
total: number;
|
|
@@ -67,8 +67,8 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
67
67
|
setTimeout(() => inputRef.current?.select(), 0);
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
const handleInputChange = (
|
|
71
|
-
const value =
|
|
70
|
+
const handleInputChange = (v: string) => {
|
|
71
|
+
const value = v.replace(/[^\d]/g, "");
|
|
72
72
|
setInputValue(value);
|
|
73
73
|
};
|
|
74
74
|
|
|
@@ -90,19 +90,12 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
90
90
|
return (
|
|
91
91
|
<div className="flex w-full items-center justify-between gap-3">
|
|
92
92
|
<div className="flex items-center gap-1">
|
|
93
|
-
<Button
|
|
94
|
-
className="
|
|
95
|
-
disabled={page === 1}
|
|
96
|
-
onClick={() => onChange?.(page - 1)}
|
|
97
|
-
size="icon"
|
|
98
|
-
variant="outline"
|
|
99
|
-
>
|
|
100
|
-
<ChevronLeft className="h-4 w-4" />
|
|
93
|
+
<Button className="size-button" disabled={page === 1} onClick={() => onChange?.(page - 1)} variant="outline">
|
|
94
|
+
<ChevronLeft className="size-4" />
|
|
101
95
|
</Button>
|
|
102
|
-
|
|
103
96
|
{isEditing ? (
|
|
104
97
|
<Input
|
|
105
|
-
className="
|
|
98
|
+
className="w-16 min-w-[70px] rounded text-center"
|
|
106
99
|
onBlur={handleJump}
|
|
107
100
|
onChange={handleInputChange}
|
|
108
101
|
onKeyDown={handleKeyDown}
|
|
@@ -112,31 +105,28 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
112
105
|
/>
|
|
113
106
|
) : (
|
|
114
107
|
<div
|
|
115
|
-
className="flex h-
|
|
108
|
+
className="flex h-input min-w-[70px] cursor-pointer items-center justify-center rounded-md border bg-background px-3 font-medium text-sm transition-colors hover:bg-accent"
|
|
116
109
|
onClick={handlePageClick}
|
|
117
110
|
>
|
|
118
111
|
{page} / {totalPages}
|
|
119
112
|
</div>
|
|
120
113
|
)}
|
|
121
|
-
|
|
122
114
|
<Button
|
|
123
|
-
className="
|
|
115
|
+
className="size-button"
|
|
124
116
|
disabled={page === totalPages}
|
|
125
117
|
onClick={() => onChange?.(page + 1)}
|
|
126
|
-
size="icon"
|
|
127
118
|
variant="outline"
|
|
128
119
|
>
|
|
129
|
-
<ChevronRight className="
|
|
120
|
+
<ChevronRight className="size-4" />
|
|
130
121
|
</Button>
|
|
131
122
|
</div>
|
|
132
123
|
|
|
133
124
|
<div className="hidden items-center gap-1 md:flex">
|
|
134
125
|
{pageNumbers.map((pageNum) => (
|
|
135
126
|
<Button
|
|
136
|
-
className="
|
|
127
|
+
className="min-w-button p-0"
|
|
137
128
|
key={pageNum}
|
|
138
129
|
onClick={() => onChange?.(pageNum)}
|
|
139
|
-
size="icon"
|
|
140
130
|
variant={pageNum === page ? "default" : "outline"}
|
|
141
131
|
>
|
|
142
132
|
{pageNum}
|
|
@@ -145,15 +135,11 @@ export const Pagination: FC<PaginationProps> = ({
|
|
|
145
135
|
</div>
|
|
146
136
|
|
|
147
137
|
{onPageSizeChange && (
|
|
148
|
-
<Tabs
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
</TabsTrigger>
|
|
154
|
-
))}
|
|
155
|
-
</TabsList>
|
|
156
|
-
</Tabs>
|
|
138
|
+
<Tabs
|
|
139
|
+
items={pageSizeOptions.map((option) => ({ label: `${option}`, value: `${option}` }))}
|
|
140
|
+
onChange={(v) => onPageSizeChange(Number(v))}
|
|
141
|
+
value={`${size}`}
|
|
142
|
+
/>
|
|
157
143
|
)}
|
|
158
144
|
</div>
|
|
159
145
|
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CSSProperties, FC, PropsWithChildren, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import { PopoverContent, PopoverTrigger, Popover as UIPopover } from "@meta-1/design/components/ui/popover";
|
|
4
|
+
import { cn } from "@meta-1/design/lib";
|
|
5
|
+
|
|
6
|
+
export type PopoverProps = PropsWithChildren<{
|
|
7
|
+
content: ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
asChild?: boolean;
|
|
10
|
+
open?: boolean;
|
|
11
|
+
onOpenChange?: (open: boolean) => void;
|
|
12
|
+
style?: CSSProperties;
|
|
13
|
+
align?: "start" | "center" | "end";
|
|
14
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
export const Popover: FC<PopoverProps> = (props) => {
|
|
19
|
+
const { children, content, className, asChild, open, onOpenChange, style, align, side, disabled } = props;
|
|
20
|
+
return (
|
|
21
|
+
<UIPopover onOpenChange={onOpenChange} open={open}>
|
|
22
|
+
<PopoverTrigger asChild={asChild} disabled={disabled}>
|
|
23
|
+
{children}
|
|
24
|
+
</PopoverTrigger>
|
|
25
|
+
<PopoverContent align={align} className={cn("rounded-popover p-popover", className)} side={side} style={style}>
|
|
26
|
+
{content}
|
|
27
|
+
</PopoverContent>
|
|
28
|
+
</UIPopover>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type FC, forwardRef, type PropsWithChildren,
|
|
1
|
+
import { type FC, forwardRef, type PropsWithChildren, useId } from "react";
|
|
2
2
|
|
|
3
3
|
import { Label } from "@meta-1/design/components/ui/label";
|
|
4
4
|
import { RadioGroupItem, RadioGroup as UIRadioGroup } from "@meta-1/design/components/ui/radio-group";
|
|
@@ -18,7 +18,7 @@ export interface RadioGroupProps extends PropsWithChildren {
|
|
|
18
18
|
export const RadioGroup: FC<RadioGroupProps> = forwardRef((props, _ref) => {
|
|
19
19
|
const { options = [], value, onChange, disabled = false } = props;
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const labelKey = useId();
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<UIRadioGroup disabled={disabled} onValueChange={onChange} value={value}>
|
|
@@ -85,12 +85,15 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>((props, _ref) =
|
|
|
85
85
|
value={currentValue as string | undefined}
|
|
86
86
|
>
|
|
87
87
|
<div className={cn("relative inline-block", allowClear && currentValue && !disabled ? "group" : "", className)}>
|
|
88
|
-
<SelectTrigger
|
|
88
|
+
<SelectTrigger
|
|
89
|
+
className={cn("flex h-select w-full rounded-select px-select", triggerClassName)}
|
|
90
|
+
size={"none" as "sm" | "default"}
|
|
91
|
+
>
|
|
89
92
|
<SelectValue placeholder={placeholder} />
|
|
90
93
|
</SelectTrigger>
|
|
91
94
|
{allowClear && currentValue && !disabled && (
|
|
92
95
|
<div
|
|
93
|
-
className="absolute top-0 right-0 z-50 hidden h-full cursor-pointer items-center justify-center px-
|
|
96
|
+
className="absolute top-0 right-0 z-50 hidden h-full cursor-pointer items-center justify-center px-2 group-hover:flex"
|
|
94
97
|
onClick={clear}
|
|
95
98
|
>
|
|
96
99
|
<XIcon className="size-4 opacity-50" />
|
|
@@ -100,6 +103,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>((props, _ref) =
|
|
|
100
103
|
<SelectContent
|
|
101
104
|
align={props.align}
|
|
102
105
|
alignOffset={props.alignOffset}
|
|
106
|
+
className="rounded-select"
|
|
103
107
|
side={props.side}
|
|
104
108
|
sideOffset={props.sideOffset}
|
|
105
109
|
>
|