@meta-1/design 0.0.199 → 0.0.200
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 -35
- 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
|
@@ -6,10 +6,10 @@ import get from "lodash/get";
|
|
|
6
6
|
import remove from "lodash/remove";
|
|
7
7
|
|
|
8
8
|
import { Button } from "@meta-1/design/components/ui/button";
|
|
9
|
-
import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from "@meta-1/design/components/ui/command";
|
|
10
|
-
import { Popover, PopoverContent, PopoverTrigger } from "@meta-1/design/components/ui/popover";
|
|
11
9
|
import { Skeleton } from "@meta-1/design/components/ui/skeleton";
|
|
10
|
+
import { Command, type CommandItemProps } from "@meta-1/design/components/uix/command";
|
|
12
11
|
import { UIXContext } from "@meta-1/design/components/uix/config-provider";
|
|
12
|
+
import { Popover } from "@meta-1/design/components/uix/popover";
|
|
13
13
|
import { Spin } from "@meta-1/design/components/uix/spin";
|
|
14
14
|
import { useSize } from "@meta-1/design/hooks";
|
|
15
15
|
import { cn } from "@meta-1/design/lib";
|
|
@@ -63,8 +63,8 @@ function SelectedLabels({
|
|
|
63
63
|
// biome-ignore lint/suspicious/noExplicitAny: <options>
|
|
64
64
|
const label = options.find((option: any) => String(option.value) === v)?.label || v;
|
|
65
65
|
return label ? (
|
|
66
|
-
<div className="my-0.5 mr-1 rounded bg-secondary px-2 py-[3px] text-sm" key={v}>
|
|
67
|
-
{label}
|
|
66
|
+
<div className="my-0.5 mr-1 max-w-[200px] rounded bg-secondary px-2 py-[3px] text-sm" key={v}>
|
|
67
|
+
<span className="block truncate">{label}</span>
|
|
68
68
|
</div>
|
|
69
69
|
) : null;
|
|
70
70
|
})}
|
|
@@ -118,70 +118,6 @@ function handleSelect<Data>(
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
function ComboSelectCommandList<Data>({
|
|
122
|
-
loading,
|
|
123
|
-
options,
|
|
124
|
-
selectedValues,
|
|
125
|
-
multiple,
|
|
126
|
-
limit,
|
|
127
|
-
setSelectedValues,
|
|
128
|
-
setValueState,
|
|
129
|
-
onChange,
|
|
130
|
-
value,
|
|
131
|
-
setOpen,
|
|
132
|
-
}: {
|
|
133
|
-
loading: boolean;
|
|
134
|
-
options: ComboSelectOptionProps<Data>[];
|
|
135
|
-
selectedValues: string[];
|
|
136
|
-
multiple: boolean;
|
|
137
|
-
limit: number;
|
|
138
|
-
setSelectedValues: (v: string[]) => void;
|
|
139
|
-
setValueState: (v: string) => void;
|
|
140
|
-
onChange?: (v: ComboSelectValueType | ComboSelectValueType[]) => void;
|
|
141
|
-
onSearch?: (v: string) => void;
|
|
142
|
-
value: string | string[];
|
|
143
|
-
setOpen: (v: boolean) => void;
|
|
144
|
-
}) {
|
|
145
|
-
return (
|
|
146
|
-
<CommandList>
|
|
147
|
-
{loading
|
|
148
|
-
? null
|
|
149
|
-
: options.map((option) => {
|
|
150
|
-
const optionValueStr = String(option.value);
|
|
151
|
-
const isSelected = selectedValues.includes(optionValueStr);
|
|
152
|
-
return (
|
|
153
|
-
<CommandItem
|
|
154
|
-
key={option.value}
|
|
155
|
-
onSelect={() =>
|
|
156
|
-
handleSelect(
|
|
157
|
-
optionValueStr,
|
|
158
|
-
multiple,
|
|
159
|
-
isSelected,
|
|
160
|
-
selectedValues,
|
|
161
|
-
limit,
|
|
162
|
-
setSelectedValues,
|
|
163
|
-
setValueState,
|
|
164
|
-
onChange!,
|
|
165
|
-
setOpen,
|
|
166
|
-
options,
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
value={optionValueStr}
|
|
170
|
-
>
|
|
171
|
-
{multiple ? <Checkbox checked={isSelected} /> : null}
|
|
172
|
-
{option.label}
|
|
173
|
-
{multiple ? null : (
|
|
174
|
-
<CheckIcon
|
|
175
|
-
className={cn("ml-auto h-4 w-4", value === optionValueStr ? "opacity-100" : "opacity-0")}
|
|
176
|
-
/>
|
|
177
|
-
)}
|
|
178
|
-
</CommandItem>
|
|
179
|
-
);
|
|
180
|
-
})}
|
|
181
|
-
</CommandList>
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
121
|
type ComboSelectButtonProps<Data> = {
|
|
186
122
|
multiple: boolean;
|
|
187
123
|
selectedValues: string[];
|
|
@@ -223,9 +159,9 @@ const ComboSelectButton = forwardRef(
|
|
|
223
159
|
return (
|
|
224
160
|
<Button
|
|
225
161
|
className={cn(
|
|
226
|
-
"group h-
|
|
162
|
+
"group h-select min-w-[150px] items-center justify-between rounded-select px-select align-middle transition-none hover:bg-secondary/40",
|
|
227
163
|
multiple ? "border-dashed" : null,
|
|
228
|
-
multiple && selectedValues && selectedValues.length ? "h-auto" : null,
|
|
164
|
+
multiple && selectedValues && selectedValues.length ? "h-auto p-0.5" : null,
|
|
229
165
|
className,
|
|
230
166
|
)}
|
|
231
167
|
disabled={disabled}
|
|
@@ -234,13 +170,18 @@ const ComboSelectButton = forwardRef(
|
|
|
234
170
|
type="button"
|
|
235
171
|
variant="outline"
|
|
236
172
|
>
|
|
237
|
-
<div
|
|
173
|
+
<div
|
|
174
|
+
className={cn(
|
|
175
|
+
"flex min-h-7.5 flex-1 flex-wrap items-center justify-start overflow-hidden",
|
|
176
|
+
multiple ? "-my-0.5" : null,
|
|
177
|
+
)}
|
|
178
|
+
>
|
|
238
179
|
{initLoading ? (
|
|
239
180
|
<Skeleton className="h-6 w-full min-w-20" />
|
|
240
181
|
) : multiple ? (
|
|
241
182
|
<SelectedLabels options={options} placeholderDom={placeholderDom} selectedValues={selectedValues} />
|
|
242
183
|
) : (
|
|
243
|
-
<span>
|
|
184
|
+
<span className="truncate">
|
|
244
185
|
{valueState
|
|
245
186
|
? options.find((option) => String(option.value) === valueState)?.label || valueState
|
|
246
187
|
: placeholderDom}
|
|
@@ -329,64 +270,93 @@ export function ComboSelect<Data = unknown>(props: ComboSelectProps<Data>) {
|
|
|
329
270
|
|
|
330
271
|
const placeholderDom = <span className="font-normal text-muted-foreground">{placeholder}</span>;
|
|
331
272
|
|
|
273
|
+
const commandItems = useMemo<CommandItemProps[]>(() => {
|
|
274
|
+
if (loading) {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
return options.map((option) => {
|
|
278
|
+
const optionValueStr = String(option.value);
|
|
279
|
+
const isSelected = selectedValues.includes(optionValueStr);
|
|
280
|
+
const currentValue = valueState || selectedValues;
|
|
281
|
+
const isCurrentValue = Array.isArray(currentValue)
|
|
282
|
+
? currentValue.includes(optionValueStr)
|
|
283
|
+
: currentValue === optionValueStr;
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
value: optionValueStr,
|
|
287
|
+
label: (
|
|
288
|
+
<>
|
|
289
|
+
{multiple ? <Checkbox checked={isSelected} /> : null}
|
|
290
|
+
{option.label}
|
|
291
|
+
{multiple ? null : (
|
|
292
|
+
<CheckIcon className={cn("ml-auto h-4 w-4", isCurrentValue ? "opacity-100" : "opacity-0")} />
|
|
293
|
+
)}
|
|
294
|
+
</>
|
|
295
|
+
),
|
|
296
|
+
onSelect: () => {
|
|
297
|
+
handleSelect(
|
|
298
|
+
optionValueStr,
|
|
299
|
+
multiple,
|
|
300
|
+
isSelected,
|
|
301
|
+
selectedValues,
|
|
302
|
+
limit,
|
|
303
|
+
setSelectedValues,
|
|
304
|
+
setValueState,
|
|
305
|
+
onChange!,
|
|
306
|
+
setOpen,
|
|
307
|
+
options,
|
|
308
|
+
);
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
}, [loading, options, selectedValues, multiple, valueState, limit, onChange, setOpen]);
|
|
313
|
+
|
|
314
|
+
const content = (
|
|
315
|
+
<Command
|
|
316
|
+
className="border-none"
|
|
317
|
+
empty={empty}
|
|
318
|
+
filter={(value, search) =>
|
|
319
|
+
filter(
|
|
320
|
+
value,
|
|
321
|
+
search,
|
|
322
|
+
options.find((option) => String(option.value) === value),
|
|
323
|
+
)
|
|
324
|
+
? 1
|
|
325
|
+
: 0
|
|
326
|
+
}
|
|
327
|
+
items={commandItems}
|
|
328
|
+
loading={loading}
|
|
329
|
+
loadingContent={
|
|
330
|
+
<div className="px-2">
|
|
331
|
+
<Skeleton className="my-2 h-6 w-full" />
|
|
332
|
+
<Skeleton className="my-2 h-6 w-full" />
|
|
333
|
+
<Skeleton className="my-2 h-6 w-full" />
|
|
334
|
+
</div>
|
|
335
|
+
}
|
|
336
|
+
searchInputProps={search ? { className: "h-9", onValueChange: onSearch } : undefined}
|
|
337
|
+
searchPlaceholder={searchPlaceholder}
|
|
338
|
+
showSearch={search}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
332
341
|
return (
|
|
333
|
-
<Popover onOpenChange={setOpen} open={open}>
|
|
334
|
-
<
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
/>
|
|
352
|
-
</PopoverTrigger>
|
|
353
|
-
<PopoverContent className="p-0" style={{ width: size.width }}>
|
|
354
|
-
<Command
|
|
355
|
-
filter={(value, search) =>
|
|
356
|
-
filter(
|
|
357
|
-
value,
|
|
358
|
-
search,
|
|
359
|
-
options.find((option) => String(option.value) === value),
|
|
360
|
-
)
|
|
361
|
-
? 1
|
|
362
|
-
: 0
|
|
363
|
-
}
|
|
364
|
-
>
|
|
365
|
-
{search ? <CommandInput className="h-9" onValueChange={onSearch} placeholder={searchPlaceholder} /> : null}
|
|
366
|
-
{loading ? (
|
|
367
|
-
<div className="px-2">
|
|
368
|
-
<Skeleton className="my-2 h-6 w-full" />
|
|
369
|
-
<Skeleton className="my-2 h-6 w-full" />
|
|
370
|
-
<Skeleton className="my-2 h-6 w-full" />
|
|
371
|
-
</div>
|
|
372
|
-
) : (
|
|
373
|
-
<CommandEmpty>{empty}</CommandEmpty>
|
|
374
|
-
)}
|
|
375
|
-
<ComboSelectCommandList
|
|
376
|
-
limit={limit}
|
|
377
|
-
loading={loading}
|
|
378
|
-
multiple={multiple}
|
|
379
|
-
onChange={onChange}
|
|
380
|
-
onSearch={onSearch}
|
|
381
|
-
options={options}
|
|
382
|
-
selectedValues={selectedValues}
|
|
383
|
-
setOpen={setOpen}
|
|
384
|
-
setSelectedValues={setSelectedValues}
|
|
385
|
-
setValueState={setValueState}
|
|
386
|
-
value={valueState || selectedValues}
|
|
387
|
-
/>
|
|
388
|
-
</Command>
|
|
389
|
-
</PopoverContent>
|
|
342
|
+
<Popover asChild className="p-0" content={content} onOpenChange={setOpen} open={open} style={{ width: size.width }}>
|
|
343
|
+
<ComboSelectButton
|
|
344
|
+
className={className}
|
|
345
|
+
disabled={disabled}
|
|
346
|
+
initLoading={initLoading}
|
|
347
|
+
loading={loading}
|
|
348
|
+
multiple={multiple}
|
|
349
|
+
onChange={onChange}
|
|
350
|
+
onSearch={onSearch}
|
|
351
|
+
options={options}
|
|
352
|
+
placeholderDom={placeholderDom}
|
|
353
|
+
ref={containerRef}
|
|
354
|
+
selectedValues={selectedValues}
|
|
355
|
+
setSelectedValues={setSelectedValues}
|
|
356
|
+
setValueState={setValueState}
|
|
357
|
+
showClear={showClear}
|
|
358
|
+
valueState={valueState}
|
|
359
|
+
/>
|
|
390
360
|
</Popover>
|
|
391
361
|
);
|
|
392
362
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
import { FC, useContext, useMemo } from "react";
|
|
3
|
+
import get from "lodash/get";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
CommandEmpty,
|
|
7
|
+
CommandGroup,
|
|
8
|
+
CommandInput,
|
|
9
|
+
CommandItem,
|
|
10
|
+
CommandList,
|
|
11
|
+
CommandSeparator,
|
|
12
|
+
CommandShortcut,
|
|
13
|
+
Command as UICommand,
|
|
14
|
+
} from "@meta-1/design/components/ui/command";
|
|
15
|
+
import { UIXContext } from "@meta-1/design/components/uix/config-provider";
|
|
16
|
+
import { cn } from "@meta-1/design/lib/utils";
|
|
17
|
+
|
|
18
|
+
export type CommandItemProps = {
|
|
19
|
+
label?: React.ReactNode;
|
|
20
|
+
shortcut?: string;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
group?: string;
|
|
23
|
+
value?: string;
|
|
24
|
+
onSelect?: (value: string) => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type CommandProps = {
|
|
28
|
+
className?: string;
|
|
29
|
+
children?: React.ReactNode;
|
|
30
|
+
showSearch?: boolean;
|
|
31
|
+
searchPlaceholder?: string;
|
|
32
|
+
empty?: React.ReactNode;
|
|
33
|
+
items?: CommandItemProps[];
|
|
34
|
+
filter?: ComponentProps<typeof UICommand>["filter"];
|
|
35
|
+
loading?: boolean;
|
|
36
|
+
loadingContent?: React.ReactNode;
|
|
37
|
+
searchInputProps?: ComponentProps<typeof CommandInput>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Command: FC<CommandProps> = ({
|
|
41
|
+
className,
|
|
42
|
+
children,
|
|
43
|
+
showSearch = true,
|
|
44
|
+
searchPlaceholder,
|
|
45
|
+
empty,
|
|
46
|
+
items = [],
|
|
47
|
+
filter,
|
|
48
|
+
loading = false,
|
|
49
|
+
loadingContent,
|
|
50
|
+
searchInputProps,
|
|
51
|
+
}) => {
|
|
52
|
+
const config = useContext(UIXContext);
|
|
53
|
+
const defaultEmpty = empty || get(config.locale, "Command.empty");
|
|
54
|
+
const defaultSearchPlaceholder = searchPlaceholder || get(config.locale, "Command.searchPlaceholder");
|
|
55
|
+
const groupedItems = useMemo(() => {
|
|
56
|
+
const grouped: Record<string, CommandItemProps[]> = {};
|
|
57
|
+
const ungrouped: CommandItemProps[] = [];
|
|
58
|
+
|
|
59
|
+
items.forEach((item) => {
|
|
60
|
+
if (item.group) {
|
|
61
|
+
if (!grouped[item.group]) {
|
|
62
|
+
grouped[item.group] = [];
|
|
63
|
+
}
|
|
64
|
+
grouped[item.group].push(item);
|
|
65
|
+
} else {
|
|
66
|
+
ungrouped.push(item);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return { grouped, ungrouped };
|
|
71
|
+
}, [items]);
|
|
72
|
+
|
|
73
|
+
const groupKeys = Object.keys(groupedItems.grouped);
|
|
74
|
+
const ungroupedItems = groupedItems.ungrouped;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<UICommand className={cn("rounded-command border", className)} filter={filter}>
|
|
78
|
+
{showSearch && <CommandInput placeholder={defaultSearchPlaceholder} {...searchInputProps} />}
|
|
79
|
+
<CommandList>
|
|
80
|
+
{loading ? (
|
|
81
|
+
loadingContent || <CommandEmpty>{defaultEmpty}</CommandEmpty>
|
|
82
|
+
) : (
|
|
83
|
+
<>
|
|
84
|
+
<CommandEmpty>{defaultEmpty}</CommandEmpty>
|
|
85
|
+
{children}
|
|
86
|
+
{ungroupedItems.length > 0 &&
|
|
87
|
+
ungroupedItems.map((item, index) => (
|
|
88
|
+
<CommandItem
|
|
89
|
+
className="rounded-command p-command"
|
|
90
|
+
disabled={item.disabled}
|
|
91
|
+
key={item.value || index}
|
|
92
|
+
onSelect={() => item.onSelect?.(item.value || String(index))}
|
|
93
|
+
value={item.value}
|
|
94
|
+
>
|
|
95
|
+
{item.label}
|
|
96
|
+
{item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
|
|
97
|
+
</CommandItem>
|
|
98
|
+
))}
|
|
99
|
+
{groupKeys.map((groupKey, groupIndex) => {
|
|
100
|
+
const groupItems = groupedItems.grouped[groupKey];
|
|
101
|
+
const shouldShowSeparator = groupIndex > 0 || (groupIndex === 0 && ungroupedItems.length > 0);
|
|
102
|
+
return (
|
|
103
|
+
<div key={groupKey}>
|
|
104
|
+
{shouldShowSeparator && <CommandSeparator />}
|
|
105
|
+
<CommandGroup heading={groupKey}>
|
|
106
|
+
{groupItems.map((item, itemIndex) => (
|
|
107
|
+
<CommandItem
|
|
108
|
+
disabled={item.disabled}
|
|
109
|
+
key={item.value || `${groupKey}-${itemIndex}`}
|
|
110
|
+
onSelect={() => item.onSelect?.(item.value || `${groupKey}-${itemIndex}`)}
|
|
111
|
+
value={item.value}
|
|
112
|
+
>
|
|
113
|
+
{item.label}
|
|
114
|
+
{item.shortcut && <CommandShortcut>{item.shortcut}</CommandShortcut>}
|
|
115
|
+
</CommandItem>
|
|
116
|
+
))}
|
|
117
|
+
</CommandGroup>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
123
|
+
</CommandList>
|
|
124
|
+
</UICommand>
|
|
125
|
+
);
|
|
126
|
+
};
|