@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.
Files changed (43) hide show
  1. package/package.json +3 -1
  2. package/src/assets/locales/en-us.ts +4 -0
  3. package/src/assets/locales/zh-cn.ts +4 -0
  4. package/src/assets/locales/zh-tw.ts +4 -0
  5. package/src/assets/style/theme.css +72 -21
  6. package/src/components/ui/button.tsx +28 -18
  7. package/src/components/uix/action/index.tsx +7 -5
  8. package/src/components/uix/action/style.css +21 -0
  9. package/src/components/uix/alert/index.tsx +5 -5
  10. package/src/components/uix/alert-dialog/index.tsx +56 -16
  11. package/src/components/uix/badge/index.tsx +8 -2
  12. package/src/components/uix/button/index.tsx +7 -5
  13. package/src/components/uix/card/index.tsx +7 -4
  14. package/src/components/uix/checkbox-group/index.tsx +3 -4
  15. package/src/components/uix/combo-select/index.tsx +99 -129
  16. package/src/components/uix/command/index.tsx +126 -0
  17. package/src/components/uix/data-grid/index.tsx +625 -0
  18. package/src/components/uix/data-grid/overlays.tsx +26 -0
  19. package/src/components/uix/data-grid/style.css +6 -0
  20. package/src/components/uix/data-table/index.tsx +10 -7
  21. package/src/components/uix/date-picker/index.tsx +55 -46
  22. package/src/components/uix/date-range-picker/index.tsx +116 -36
  23. package/src/components/uix/dialog/index.tsx +5 -5
  24. package/src/components/uix/dropdown/index.tsx +1 -1
  25. package/src/components/uix/input/index.tsx +23 -0
  26. package/src/components/uix/message/index.tsx +4 -4
  27. package/src/components/uix/pagination/index.tsx +17 -31
  28. package/src/components/uix/popover/index.tsx +30 -0
  29. package/src/components/uix/radio-group/index.tsx +2 -2
  30. package/src/components/uix/select/index.tsx +6 -2
  31. package/src/components/uix/sheet/index.tsx +76 -0
  32. package/src/components/uix/tabs/index.tsx +38 -0
  33. package/src/components/uix/tags-input/index.tsx +22 -3
  34. package/src/components/uix/textarea/index.tsx +23 -0
  35. package/src/components/uix/tooltip/index.tsx +5 -4
  36. package/src/components/uix/tree/style.css +1 -0
  37. package/src/components/uix/tree-select/index.tsx +59 -64
  38. package/src/components/uix/uploader/index.tsx +1 -1
  39. package/src/components/uix/value-formatter/index.tsx +40 -46
  40. package/src/index.ts +19 -35
  41. package/src/lib/utils.ts +50 -1
  42. package/src/components/uix/breadcrumbs/index.tsx +0 -38
  43. 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-9 min-w-[150px] items-center justify-between px-2 py-1 align-middle hover:bg-secondary/40",
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 className={cn("flex min-h-7.5 flex-1 flex-wrap items-center justify-start", multiple ? "-my-0.5" : null)}>
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
- <PopoverTrigger asChild disabled={disabled}>
335
- <ComboSelectButton
336
- className={className}
337
- disabled={disabled}
338
- initLoading={initLoading}
339
- loading={loading}
340
- multiple={multiple}
341
- onChange={onChange}
342
- onSearch={onSearch}
343
- options={options}
344
- placeholderDom={placeholderDom}
345
- ref={containerRef}
346
- selectedValues={selectedValues}
347
- setSelectedValues={setSelectedValues}
348
- setValueState={setValueState}
349
- showClear={showClear}
350
- valueState={valueState}
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
+ };