@lark-apaas/coding-template-nestjs-react-fullstack 0.1.36-alpha.20260903095202 → 0.1.36-alpha.20260903185731

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 (112) hide show
  1. package/package.json +1 -1
  2. package/template/client/src/components/ui/markdown.tsx +43 -0
  3. package/template/client/src/index.css +0 -1
  4. package/template/package-lock.json +5783 -13022
  5. package/template/package.json +5 -68
  6. package/template/client/src/components/business-ui/README.md +0 -519
  7. package/template/client/src/components/business-ui/api/chats/queries.ts +0 -39
  8. package/template/client/src/components/business-ui/api/chats/service.ts +0 -29
  9. package/template/client/src/components/business-ui/api/departments/queries.ts +0 -42
  10. package/template/client/src/components/business-ui/api/departments/service.ts +0 -18
  11. package/template/client/src/components/business-ui/api/files/service.ts +0 -28
  12. package/template/client/src/components/business-ui/api/user-profiles/queries.ts +0 -42
  13. package/template/client/src/components/business-ui/api/user-profiles/service.ts +0 -23
  14. package/template/client/src/components/business-ui/api/users/queries.ts +0 -34
  15. package/template/client/src/components/business-ui/api/users/service.ts +0 -40
  16. package/template/client/src/components/business-ui/chat-select/README.md +0 -128
  17. package/template/client/src/components/business-ui/chat-select/chat-item.tsx +0 -85
  18. package/template/client/src/components/business-ui/chat-select/chat-select-tag.tsx +0 -83
  19. package/template/client/src/components/business-ui/chat-select/chat-select.tsx +0 -197
  20. package/template/client/src/components/business-ui/chat-select/index.tsx +0 -12
  21. package/template/client/src/components/business-ui/chat-select/types.ts +0 -102
  22. package/template/client/src/components/business-ui/chat-select/use-chat-value.ts +0 -180
  23. package/template/client/src/components/business-ui/chat-select/utils.ts +0 -81
  24. package/template/client/src/components/business-ui/department-select/department-item.tsx +0 -55
  25. package/template/client/src/components/business-ui/department-select/department-select-field.tsx +0 -86
  26. package/template/client/src/components/business-ui/department-select/department-select-tag.tsx +0 -56
  27. package/template/client/src/components/business-ui/department-select/department-select.tsx +0 -168
  28. package/template/client/src/components/business-ui/department-select/icon-department.tsx +0 -22
  29. package/template/client/src/components/business-ui/department-select/index.tsx +0 -7
  30. package/template/client/src/components/business-ui/department-select/types.ts +0 -15
  31. package/template/client/src/components/business-ui/department-select/utils.ts +0 -17
  32. package/template/client/src/components/business-ui/entity-combobox/base-combobox-content.tsx +0 -35
  33. package/template/client/src/components/business-ui/entity-combobox/base-combobox-empty.tsx +0 -28
  34. package/template/client/src/components/business-ui/entity-combobox/base-combobox-error.tsx +0 -35
  35. package/template/client/src/components/business-ui/entity-combobox/base-combobox-item.tsx +0 -55
  36. package/template/client/src/components/business-ui/entity-combobox/base-combobox-list.tsx +0 -174
  37. package/template/client/src/components/business-ui/entity-combobox/base-combobox-loading.tsx +0 -19
  38. package/template/client/src/components/business-ui/entity-combobox/base-combobox-search.tsx +0 -31
  39. package/template/client/src/components/business-ui/entity-combobox/base-combobox-trigger.tsx +0 -281
  40. package/template/client/src/components/business-ui/entity-combobox/base-combobox.tsx +0 -132
  41. package/template/client/src/components/business-ui/entity-combobox/context.tsx +0 -19
  42. package/template/client/src/components/business-ui/entity-combobox/entity-combobox.tsx +0 -145
  43. package/template/client/src/components/business-ui/entity-combobox/highlight-text.tsx +0 -52
  44. package/template/client/src/components/business-ui/entity-combobox/hooks.tsx +0 -21
  45. package/template/client/src/components/business-ui/entity-combobox/index.tsx +0 -31
  46. package/template/client/src/components/business-ui/entity-combobox/item-pill.tsx +0 -179
  47. package/template/client/src/components/business-ui/entity-combobox/popover-wrapper.tsx +0 -149
  48. package/template/client/src/components/business-ui/entity-combobox/search-trigger.tsx +0 -262
  49. package/template/client/src/components/business-ui/entity-combobox/shared-types.ts +0 -296
  50. package/template/client/src/components/business-ui/entity-combobox/size-variants.tsx +0 -322
  51. package/template/client/src/components/business-ui/entity-combobox/types.ts +0 -246
  52. package/template/client/src/components/business-ui/entity-combobox/use-fetch-data.tsx +0 -81
  53. package/template/client/src/components/business-ui/entity-combobox/use-infinite-scroll.tsx +0 -99
  54. package/template/client/src/components/business-ui/entity-combobox/use-popover-outside-click.tsx +0 -32
  55. package/template/client/src/components/business-ui/form/checkbox-field.tsx +0 -83
  56. package/template/client/src/components/business-ui/form/context.tsx +0 -38
  57. package/template/client/src/components/business-ui/form/field-layout.tsx +0 -91
  58. package/template/client/src/components/business-ui/form/form.tsx +0 -54
  59. package/template/client/src/components/business-ui/form/hooks/form-context.tsx +0 -4
  60. package/template/client/src/components/business-ui/form/hooks/form-utils.ts +0 -23
  61. package/template/client/src/components/business-ui/form/hooks/form.tsx +0 -40
  62. package/template/client/src/components/business-ui/form/index.tsx +0 -4
  63. package/template/client/src/components/business-ui/form/input-field.tsx +0 -74
  64. package/template/client/src/components/business-ui/form/radio-group-field.tsx +0 -138
  65. package/template/client/src/components/business-ui/form/select-field.tsx +0 -155
  66. package/template/client/src/components/business-ui/form/switch-field.tsx +0 -66
  67. package/template/client/src/components/business-ui/form/textarea-field.tsx +0 -72
  68. package/template/client/src/components/business-ui/form/types.ts +0 -32
  69. package/template/client/src/components/business-ui/tiptap-editor/README.md +0 -324
  70. package/template/client/src/components/business-ui/tiptap-editor/components/attachment-toolbar-button.tsx +0 -74
  71. package/template/client/src/components/business-ui/tiptap-editor/components/blockquote-toolbar-button.tsx +0 -41
  72. package/template/client/src/components/business-ui/tiptap-editor/components/code-block-toolbar-button.tsx +0 -41
  73. package/template/client/src/components/business-ui/tiptap-editor/components/color-highlight-toolbar-button.tsx +0 -141
  74. package/template/client/src/components/business-ui/tiptap-editor/components/heading-toolbar-button.tsx +0 -99
  75. package/template/client/src/components/business-ui/tiptap-editor/components/horizontal-rule-toolbar-button.tsx +0 -39
  76. package/template/client/src/components/business-ui/tiptap-editor/components/image-upload-toolbar-button.tsx +0 -65
  77. package/template/client/src/components/business-ui/tiptap-editor/components/link-edit-form.tsx +0 -127
  78. package/template/client/src/components/business-ui/tiptap-editor/components/link-hover-toolbar.tsx +0 -380
  79. package/template/client/src/components/business-ui/tiptap-editor/components/link-toolbar-button.tsx +0 -96
  80. package/template/client/src/components/business-ui/tiptap-editor/components/list-toolbar-button.tsx +0 -75
  81. package/template/client/src/components/business-ui/tiptap-editor/components/mark-toolbar-button.tsx +0 -118
  82. package/template/client/src/components/business-ui/tiptap-editor/components/text-align-toolbar-button.tsx +0 -84
  83. package/template/client/src/components/business-ui/tiptap-editor/components/undo-redo-toolbar-button.tsx +0 -54
  84. package/template/client/src/components/business-ui/tiptap-editor/extensions/attachment.tsx +0 -539
  85. package/template/client/src/components/business-ui/tiptap-editor/extensions/code-block-shiki.tsx +0 -236
  86. package/template/client/src/components/business-ui/tiptap-editor/extensions/complete-kit.ts +0 -260
  87. package/template/client/src/components/business-ui/tiptap-editor/extensions/image.tsx +0 -456
  88. package/template/client/src/components/business-ui/tiptap-editor/hooks/use-tiptap-editor.ts +0 -47
  89. package/template/client/src/components/business-ui/tiptap-editor/index.ts +0 -38
  90. package/template/client/src/components/business-ui/tiptap-editor/tiptap-editor-complete.tsx +0 -112
  91. package/template/client/src/components/business-ui/tiptap-editor/tiptap-editor.tsx +0 -169
  92. package/template/client/src/components/business-ui/types/user.ts +0 -74
  93. package/template/client/src/components/business-ui/user-display/index.tsx +0 -2
  94. package/template/client/src/components/business-ui/user-display/overflow-tooltip-text.tsx +0 -90
  95. package/template/client/src/components/business-ui/user-display/type.ts +0 -27
  96. package/template/client/src/components/business-ui/user-display/user-display.tsx +0 -99
  97. package/template/client/src/components/business-ui/user-display/user-with-avatar.tsx +0 -158
  98. package/template/client/src/components/business-ui/user-display/utils.ts +0 -37
  99. package/template/client/src/components/business-ui/user-profile/error-image.tsx +0 -302
  100. package/template/client/src/components/business-ui/user-profile/user-external-script.ts +0 -73
  101. package/template/client/src/components/business-ui/user-profile/user-profile.tsx +0 -370
  102. package/template/client/src/components/business-ui/user-select/index.tsx +0 -28
  103. package/template/client/src/components/business-ui/user-select/types.ts +0 -109
  104. package/template/client/src/components/business-ui/user-select/use-user-value.ts +0 -160
  105. package/template/client/src/components/business-ui/user-select/user-item.tsx +0 -98
  106. package/template/client/src/components/business-ui/user-select/user-pill.tsx +0 -140
  107. package/template/client/src/components/business-ui/user-select/user-select-tag.tsx +0 -82
  108. package/template/client/src/components/business-ui/user-select/user-select.tsx +0 -359
  109. package/template/client/src/components/business-ui/user-select/utils.tsx +0 -188
  110. package/template/client/src/components/business-ui/utils/user.ts +0 -72
  111. package/template/client/src/components/ui/streamdown.tsx +0 -186
  112. package/template/client/src/lib/shiki.ts +0 -92
@@ -1,179 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
-
5
- import {
6
- itemPillTextVariants,
7
- itemPillVariants,
8
- tagAvatarVariants,
9
- type ComboboxSize,
10
- } from '@client/src/components/business-ui/entity-combobox/size-variants';
11
- import { cn } from '@/lib/utils';
12
- import {
13
- Avatar,
14
- AvatarFallback,
15
- AvatarImage,
16
- } from '@client/src/components/ui/avatar';
17
- import { Badge } from '@client/src/components/ui/badge';
18
-
19
- export type ItemPillProps = {
20
- /**
21
- * 显示的文本
22
- */
23
- label: string;
24
-
25
- /**
26
- * 尺寸
27
- * @default "medium"
28
- */
29
- size?: ComboboxSize;
30
-
31
- /**
32
- * 头像 URL
33
- */
34
- avatarUrl?: string;
35
-
36
- /**
37
- * 头像内容(用于自定义头像显示)
38
- */
39
- avatar?: React.ReactNode;
40
-
41
- /**
42
- * 是否显示头像占位符(当没有头像 URL 时显示)
43
- * @default false
44
- *
45
- */
46
- avatarFallback?: boolean;
47
-
48
- /**
49
- * 自定义样式
50
- */
51
- className?: string;
52
- /**
53
- * 是否禁用
54
- */
55
- disabled?: boolean;
56
- /**
57
- * 最大文本长度
58
- */
59
- maxTextLength?: number;
60
-
61
- /**
62
- * 后缀
63
- */
64
- suffix?: React.ReactNode;
65
- };
66
-
67
- // 检查是否是 16 进制 RGB 颜色(如 #RRGGBB 或 #RGB)
68
- export const isHexColor = (str?: string): boolean => {
69
- if (!str) return false;
70
- return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(str);
71
- };
72
-
73
- /**
74
- * renderPillAvatar 的参数类型
75
- */
76
- export type RenderPillAvatarOptions = {
77
- /**
78
- * 头像 URL
79
- */
80
- avatarUrl?: string;
81
- /**
82
- * 显示的文本(用于 fallback 首字母)
83
- */
84
- label: string;
85
- /**
86
- * 尺寸
87
- * @default "medium"
88
- */
89
- size?: ComboboxSize;
90
- /**
91
- * 是否显示头像占位符(当没有头像 URL 时显示)
92
- * @default true
93
- */
94
- avatarFallback?: boolean;
95
- };
96
-
97
- /**
98
- * 渲染 Pill 头像的辅助函数
99
- * 可被其他组件复用(如 UserPill)
100
- */
101
- export const renderPillAvatar = ({
102
- avatarUrl,
103
- label,
104
- size = 'medium',
105
- avatarFallback = true,
106
- }: RenderPillAvatarOptions): React.ReactNode => {
107
- if (avatarUrl) {
108
- // 如果是 16 进制颜色,渲染带背景色的头像和用户名首字
109
- if (isHexColor(avatarUrl)) {
110
- return (
111
- <Avatar className={tagAvatarVariants({ size })}>
112
- <AvatarFallback style={{ backgroundColor: avatarUrl }}>
113
- {label?.charAt?.(0).toUpperCase()}
114
- </AvatarFallback>
115
- </Avatar>
116
- );
117
- }
118
- return (
119
- <Avatar className={tagAvatarVariants({ size })}>
120
- <AvatarImage src={avatarUrl} alt={label} loading="eager" />
121
- </Avatar>
122
- );
123
- }
124
-
125
- if (avatarFallback) {
126
- return (
127
- <Avatar className={tagAvatarVariants({ size })}>
128
- <AvatarFallback>{label?.charAt?.(0).toUpperCase()}</AvatarFallback>
129
- </Avatar>
130
- );
131
- }
132
-
133
- return null;
134
- };
135
-
136
- export const ItemPill: React.FC<ItemPillProps> = ({
137
- className,
138
- avatarUrl,
139
- disabled,
140
- label,
141
- maxTextLength,
142
- suffix,
143
- avatar,
144
- avatarFallback = true,
145
- size = 'medium',
146
- }) => {
147
- const displayLabel = React.useMemo(() => {
148
- if (!maxTextLength || label?.length <= maxTextLength) {
149
- return label;
150
- }
151
- return label.slice(0, maxTextLength) + '...';
152
- }, [maxTextLength, label]);
153
-
154
- const avatarElement = React.useMemo(() => {
155
- if (avatar) {
156
- return avatar;
157
- }
158
-
159
- return renderPillAvatar({ avatarUrl, label, size, avatarFallback });
160
- }, [avatar, avatarUrl, avatarFallback, label, size]);
161
-
162
- return (
163
- <Badge
164
- variant="secondary"
165
- className={cn(
166
- itemPillVariants({ size }),
167
- disabled && 'cursor-not-allowed opacity-50',
168
- className,
169
- )}
170
- >
171
- {/* 头像 */}
172
- {avatarElement}
173
- {/* 文本 */}
174
- <span className={itemPillTextVariants({ size })}>{displayLabel}</span>
175
-
176
- {suffix}
177
- </Badge>
178
- );
179
- };
@@ -1,149 +0,0 @@
1
- 'use client';
2
-
3
- import { BaseComboboxContent } from '@client/src/components/business-ui/entity-combobox/base-combobox-content';
4
- import { BaseComboboxList } from '@client/src/components/business-ui/entity-combobox/base-combobox-list';
5
- import { BaseComboboxSearch } from '@client/src/components/business-ui/entity-combobox/base-combobox-search';
6
- import { BaseComboboxTrigger } from '@client/src/components/business-ui/entity-combobox/base-combobox-trigger';
7
- import { useEntityComboboxContext } from '@client/src/components/business-ui/entity-combobox/context';
8
- import type {
9
- ItemValue,
10
- PopoverWrapperProps,
11
- } from '@client/src/components/business-ui/entity-combobox/types';
12
- import { cn } from '@/lib/utils';
13
- import { Popover, PopoverTrigger } from '@client/src/components/ui/popover';
14
-
15
- /**
16
- * 统一的浮层包装组件
17
- * 根据 triggerType 渲染不同的交互模式
18
- */
19
- export function PopoverWrapper<
20
- T = unknown,
21
- TRaw = unknown,
22
- TValue extends ItemValue<TRaw> = ItemValue<TRaw>,
23
- >(props: PopoverWrapperProps<T, TRaw, TValue>) {
24
- const {
25
- size,
26
- triggerType = 'button',
27
- renderTrigger,
28
- placeholder,
29
- maxTagCount,
30
- maxTagTextLength,
31
- tagClosable,
32
- className,
33
- classNames,
34
- placement,
35
- align,
36
- sideOffset,
37
- showSearch,
38
- searchPlaceholder,
39
- renderItem,
40
- renderTag,
41
- getItemValue,
42
- getOptionDisabled,
43
- emptyText,
44
- loadingText,
45
- onFocus,
46
- onBlur,
47
- slotProps,
48
- children,
49
- } = props;
50
-
51
- const { open, setOpen, disabled } = useEntityComboboxContext();
52
-
53
- // 处理打开状态变化,如果 disabled 则不允许打开
54
- const handleOpenChange = (newOpen: boolean) => {
55
- if (disabled && newOpen) return;
56
- setOpen(newOpen);
57
- };
58
-
59
- // 渲染 Popover 内容
60
- const renderPopoverContent = () => (
61
- <BaseComboboxContent
62
- popoverProps={slotProps?.popover}
63
- className={classNames?.popover}
64
- side={placement}
65
- align={align}
66
- sideOffset={sideOffset}
67
- >
68
- {children || (
69
- <>
70
- {(showSearch || triggerType === 'search') && (
71
- <BaseComboboxSearch
72
- placeholder={searchPlaceholder}
73
- className={classNames?.search}
74
- />
75
- )}
76
- <BaseComboboxList
77
- renderItem={renderItem}
78
- getItemValue={getItemValue}
79
- getOptionDisabled={
80
- getOptionDisabled as ((value: ItemValue) => boolean) | undefined
81
- }
82
- emptyText={emptyText}
83
- loadingText={loadingText}
84
- classNames={classNames}
85
- />
86
- </>
87
- )}
88
- </BaseComboboxContent>
89
- );
90
-
91
- // button 类型:标签在外部,Popover 只包裹加号按钮
92
- if (triggerType === 'button') {
93
- return (
94
- <div className={cn(className, classNames?.root)}>
95
- <Popover open={open} onOpenChange={handleOpenChange}>
96
- <BaseComboboxTrigger
97
- triggerType={triggerType}
98
- size={size}
99
- placeholder={placeholder}
100
- renderTrigger={renderTrigger as any}
101
- maxTagCount={maxTagCount}
102
- maxTagTextLength={maxTagTextLength}
103
- tagClosable={tagClosable}
104
- classNames={classNames}
105
- onFocus={onFocus}
106
- onBlur={onBlur}
107
- renderTag={renderTag as any}
108
- getOptionDisabled={
109
- getOptionDisabled as ((value: ItemValue) => boolean) | undefined
110
- }
111
- renderAddButton={(buttonProps) => (
112
- <PopoverTrigger asChild>{buttonProps}</PopoverTrigger>
113
- )}
114
- />
115
- {renderPopoverContent()}
116
- </Popover>
117
- </div>
118
- );
119
- }
120
-
121
- // search 和 custom 类型:整个 trigger 包裹在 Popover 中
122
- return (
123
- <div className={cn(className, classNames?.root)}>
124
- <Popover open={open} onOpenChange={handleOpenChange}>
125
- <PopoverTrigger asChild>
126
- <div>
127
- <BaseComboboxTrigger
128
- triggerType={triggerType}
129
- size={size}
130
- placeholder={placeholder}
131
- renderTrigger={renderTrigger as any}
132
- maxTagCount={maxTagCount}
133
- maxTagTextLength={maxTagTextLength}
134
- tagClosable={tagClosable}
135
- classNames={classNames}
136
- onFocus={onFocus}
137
- onBlur={onBlur}
138
- renderTag={renderTag as any}
139
- getOptionDisabled={
140
- getOptionDisabled as ((value: ItemValue) => boolean) | undefined
141
- }
142
- />
143
- </div>
144
- </PopoverTrigger>
145
- {renderPopoverContent()}
146
- </Popover>
147
- </div>
148
- );
149
- }
@@ -1,262 +0,0 @@
1
- 'use client';
2
-
3
- import { ChevronDown, ChevronUp, CircleX, X } from 'lucide-react';
4
-
5
- import { useEntityComboboxContext } from '@client/src/components/business-ui/entity-combobox/context';
6
- import {
7
- searchTagVariants,
8
- searchTriggerVariants,
9
- tagCloseIconVariants,
10
- type ComboboxSize,
11
- } from '@client/src/components/business-ui/entity-combobox/size-variants';
12
- import type {
13
- ClassNamesConfig,
14
- ItemValue,
15
- } from '@client/src/components/business-ui/entity-combobox/types';
16
- import { cn } from '@/lib/utils';
17
- import { Badge } from '@client/src/components/ui/badge';
18
- import { Button } from '@client/src/components/ui/button';
19
- import {
20
- Tooltip,
21
- TooltipContent,
22
- TooltipTrigger,
23
- } from '@client/src/components/ui/tooltip';
24
-
25
- export type SearchTriggerProps = {
26
- size?: ComboboxSize;
27
- placeholder?: string;
28
- maxTagCount?: number | 'responsive';
29
- maxTagTextLength?: number;
30
- tagClosable?: boolean;
31
- classNames?: ClassNamesConfig;
32
- onFocus?: (e: React.FocusEvent<HTMLDivElement>) => void;
33
- onBlur?: (e: React.FocusEvent<HTMLDivElement>) => void;
34
- /**
35
- * 自定义渲染单个标签
36
- * @param value 标签的值对象
37
- * @param onClose 关闭标签的回调
38
- * @param disabled 是否禁用
39
- * @returns ReactNode
40
- */
41
- renderTag?: (
42
- value: ItemValue,
43
- onClose: (value: ItemValue, e: React.MouseEvent) => void,
44
- disabled?: boolean,
45
- ) => React.ReactNode;
46
- /**
47
- * 判断选项是否禁用
48
- */
49
- getOptionDisabled?: (value: ItemValue) => boolean;
50
- ref?: React.Ref<HTMLDivElement>;
51
- };
52
-
53
- export const SearchTrigger = ({
54
- size = 'medium',
55
- placeholder = '请选择',
56
- maxTagCount,
57
- maxTagTextLength,
58
- tagClosable = true,
59
- classNames,
60
- onFocus,
61
- onBlur,
62
- renderTag,
63
- getOptionDisabled,
64
- ref,
65
- }: SearchTriggerProps) => {
66
- const {
67
- selectedValue,
68
- multiple,
69
- handleDeselect,
70
- handleClear,
71
- open,
72
- disabled,
73
- } = useEntityComboboxContext();
74
-
75
- const selectedArray = Array.isArray(selectedValue) ? selectedValue : [];
76
-
77
- // 计算显示的标签
78
- const getDisplayTags = () => {
79
- if (!multiple) return [];
80
-
81
- if (typeof maxTagCount === 'number') {
82
- return selectedArray.slice(0, maxTagCount);
83
- }
84
-
85
- // TODO: responsive 模式需要根据容器宽度计算
86
- return selectedArray;
87
- };
88
-
89
- const displayTags = getDisplayTags();
90
- const hiddenCount =
91
- multiple && typeof maxTagCount === 'number'
92
- ? Math.max(0, selectedArray.length - maxTagCount)
93
- : 0;
94
-
95
- const hiddenTags =
96
- multiple && typeof maxTagCount === 'number'
97
- ? selectedArray.slice(maxTagCount)
98
- : [];
99
-
100
- const handleTagClose = (value: ItemValue, e: React.MouseEvent) => {
101
- e.stopPropagation();
102
- if (getOptionDisabled?.(value)) return;
103
- if (!multiple) {
104
- handleClear(); // 单选模式清空
105
- } else {
106
- handleDeselect(value); // 多选模式删除指定项
107
- }
108
- };
109
-
110
- const truncateText = (text: string) => {
111
- if (!maxTagTextLength || text.length <= maxTagTextLength) {
112
- return text;
113
- }
114
- return text.slice(0, maxTagTextLength) + '...';
115
- };
116
-
117
- // 单选模式下显示选中值
118
- const displayValue =
119
- !multiple && selectedValue && !Array.isArray(selectedValue)
120
- ? selectedValue.name
121
- : '';
122
-
123
- return (
124
- <div
125
- ref={ref}
126
- tabIndex={disabled ? -1 : 0}
127
- role="combobox"
128
- aria-expanded={open}
129
- aria-controls="combobox-content"
130
- aria-disabled={disabled}
131
- data-state={open ? 'open' : 'closed'}
132
- className={cn(
133
- 'group',
134
- searchTriggerVariants({ size }),
135
- disabled && 'cursor-not-allowed bg-muted hover:border-input',
136
- classNames?.trigger,
137
- )}
138
- onFocus={disabled ? undefined : onFocus}
139
- onBlur={disabled ? undefined : onBlur}
140
- >
141
- <div className="flex min-w-0 flex-1 items-center gap-1">
142
- {!multiple && displayValue ? (
143
- renderTag ? (
144
- renderTag(
145
- selectedValue as ItemValue,
146
- handleTagClose,
147
- getOptionDisabled?.(selectedValue as ItemValue),
148
- )
149
- ) : (
150
- <span className="truncate">{displayValue}</span>
151
- )
152
- ) : multiple && selectedArray.length > 0 ? (
153
- <div className="flex flex-wrap gap-1">
154
- {displayTags.map((value) =>
155
- renderTag ? (
156
- renderTag(value, handleTagClose, getOptionDisabled?.(value))
157
- ) : (
158
- <Badge
159
- key={value.id}
160
- variant="secondary"
161
- className={cn(searchTagVariants({ size }), classNames?.tag)}
162
- >
163
- <span>{truncateText(value.name)}</span>
164
- {tagClosable && (
165
- <button
166
- type="button"
167
- className="ml-1 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100"
168
- onClick={(e) => handleTagClose(value, e)}
169
- >
170
- <X className={tagCloseIconVariants({ size })} />
171
- </button>
172
- )}
173
- </Badge>
174
- ),
175
- )}
176
- {hiddenCount > 0 && (
177
- <Tooltip delayDuration={200}>
178
- <TooltipTrigger asChild>
179
- <Badge
180
- variant="secondary"
181
- className={cn(
182
- searchTagVariants({ size }),
183
- 'cursor-pointer',
184
- )}
185
- >
186
- +{hiddenCount}
187
- </Badge>
188
- </TooltipTrigger>
189
- <TooltipContent className="w-auto max-w-80 p-2" align="start">
190
- <div className="flex flex-wrap gap-1">
191
- {hiddenTags.map((value) =>
192
- renderTag ? (
193
- renderTag(
194
- value,
195
- handleTagClose,
196
- getOptionDisabled?.(value),
197
- )
198
- ) : (
199
- <Badge
200
- key={value.id}
201
- variant="secondary"
202
- className={cn(
203
- searchTagVariants({ size }),
204
- classNames?.tag,
205
- )}
206
- >
207
- <span>{truncateText(value.name)}</span>
208
- {tagClosable && (
209
- <button
210
- type="button"
211
- className="ml-1 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100"
212
- onClick={(e) => handleTagClose(value, e)}
213
- >
214
- <X className={tagCloseIconVariants({ size })} />
215
- </button>
216
- )}
217
- </Badge>
218
- ),
219
- )}
220
- </div>
221
- </TooltipContent>
222
- </Tooltip>
223
- )}
224
- </div>
225
- ) : (
226
- <span className="text-muted-foreground">{placeholder}</span>
227
- )}
228
- </div>
229
-
230
- {selectedArray.length > 0 && (
231
- <Button
232
- variant="ghost"
233
- size="icon"
234
- data-slot="combobox-clear"
235
- disabled={disabled}
236
- aria-disabled={disabled}
237
- className={cn(
238
- 'flex h-4 w-4 items-center rounded-full text-muted-foreground opacity-0 group-hover:opacity-100 not-disabled:hover:bg-transparent not-disabled:hover:text-primary aria-disabled:opacity-0',
239
- classNames?.clear,
240
- )}
241
- onClick={(e) => {
242
- e.stopPropagation();
243
- handleClear();
244
- }}
245
- >
246
- <>
247
- <CircleX className="h-3! w-3!" />
248
- <span className="sr-only">Clear all</span>
249
- </>
250
- </Button>
251
- )}
252
-
253
- <div className={cn('ml-1', classNames?.suffix)}>
254
- {open ? (
255
- <ChevronUp className="h-4 w-4 shrink-0 opacity-50" />
256
- ) : (
257
- <ChevronDown className="h-4 w-4 shrink-0 opacity-50" />
258
- )}
259
- </div>
260
- </div>
261
- );
262
- };