@rebasepro/ui 0.17.3 → 0.18.1
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/README.md +4 -0
- package/dist/components/MultiSelect.d.ts +10 -0
- package/dist/index.es.js +2 -1
- package/dist/index.es.js.map +1 -1
- package/package.json +32 -23
- package/src/components/Alert.tsx +0 -118
- package/src/components/Autocomplete.tsx +0 -93
- package/src/components/Avatar.tsx +0 -73
- package/src/components/Badge.tsx +0 -44
- package/src/components/BooleanSwitch.tsx +0 -116
- package/src/components/BooleanSwitchWithLabel.tsx +0 -120
- package/src/components/Button.tsx +0 -110
- package/src/components/Card.tsx +0 -43
- package/src/components/CenteredView.tsx +0 -35
- package/src/components/Checkbox.tsx +0 -129
- package/src/components/Chip.tsx +0 -131
- package/src/components/CircularProgress.tsx +0 -53
- package/src/components/CircularProgressCenter.tsx +0 -27
- package/src/components/Collapse.tsx +0 -66
- package/src/components/ColorPicker.tsx +0 -140
- package/src/components/Container.tsx +0 -51
- package/src/components/DateTimeField.tsx +0 -363
- package/src/components/DebouncedTextField.tsx +0 -76
- package/src/components/Dialog.tsx +0 -159
- package/src/components/DialogActions.tsx +0 -29
- package/src/components/DialogContent.tsx +0 -27
- package/src/components/DialogTitle.tsx +0 -41
- package/src/components/ErrorBoundary.tsx +0 -236
- package/src/components/ExpandablePanel.tsx +0 -130
- package/src/components/FileUpload.tsx +0 -103
- package/src/components/FilterChip.tsx +0 -89
- package/src/components/IconButton.tsx +0 -101
- package/src/components/InfoLabel.tsx +0 -23
- package/src/components/InputLabel.tsx +0 -40
- package/src/components/Label.tsx +0 -32
- package/src/components/LoadingButton.tsx +0 -32
- package/src/components/Markdown.tsx +0 -55
- package/src/components/Menu.tsx +0 -114
- package/src/components/Menubar.tsx +0 -355
- package/src/components/MultiSelect.tsx +0 -433
- package/src/components/Paper.tsx +0 -23
- package/src/components/Popover.tsx +0 -162
- package/src/components/RadioGroup.tsx +0 -74
- package/src/components/ResizablePanels.tsx +0 -189
- package/src/components/SearchBar.tsx +0 -136
- package/src/components/Select.tsx +0 -326
- package/src/components/Separator.tsx +0 -28
- package/src/components/Sheet.tsx +0 -135
- package/src/components/Skeleton.tsx +0 -54
- package/src/components/Slider.tsx +0 -110
- package/src/components/Table.tsx +0 -178
- package/src/components/Tabs.tsx +0 -185
- package/src/components/TextField.tsx +0 -270
- package/src/components/TextareaAutosize.tsx +0 -368
- package/src/components/ToggleButtonGroup.tsx +0 -69
- package/src/components/Tooltip.tsx +0 -153
- package/src/components/Typography.tsx +0 -132
- package/src/components/VirtualTable/VirtualTable.performance.test.tsx +0 -90
- package/src/components/VirtualTable/VirtualTable.tsx +0 -700
- package/src/components/VirtualTable/VirtualTableCell.tsx +0 -59
- package/src/components/VirtualTable/VirtualTableHeader.tsx +0 -327
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +0 -250
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -339
- package/src/components/VirtualTable/VirtualTableRow.tsx +0 -51
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +0 -44
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -89
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +0 -71
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +0 -107
- package/src/components/VirtualTable/fields/VirtualTableSwitch.tsx +0 -28
- package/src/components/VirtualTable/index.tsx +0 -10
- package/src/components/VirtualTable/selection/SelectionContext.tsx +0 -36
- package/src/components/VirtualTable/selection/SelectionStore.ts +0 -54
- package/src/components/VirtualTable/types.tsx +0 -47
- package/src/components/common/SelectInputLabel.tsx +0 -23
- package/src/components/index.tsx +0 -62
- package/src/hooks/PortalContainerContext.tsx +0 -50
- package/src/hooks/index.ts +0 -7
- package/src/hooks/useDebounceCallback.tsx +0 -21
- package/src/hooks/useDebounceValue.tsx +0 -20
- package/src/hooks/useDebouncedCallback.ts +0 -39
- package/src/hooks/useInjectStyles.tsx +0 -31
- package/src/hooks/useOutsideAlerter.tsx +0 -46
- package/src/icons/GitHubIcon.tsx +0 -21
- package/src/icons/HandleIcon.tsx +0 -23
- package/src/icons/Icon.tsx +0 -33
- package/src/icons/LucideIconByName.tsx +0 -117
- package/src/icons/cool_icon_keys.ts +0 -12
- package/src/icons/icon_keys.ts +0 -1936
- package/src/icons/index.ts +0 -179
- package/src/index.css +0 -169
- package/src/index.ts +0 -47
- package/src/scripts/fixIconSizes.cjs +0 -92
- package/src/scripts/fixIconSizesToConst.cjs +0 -106
- package/src/scripts/generateIconKeys.ts +0 -41
- package/src/scripts/generateIcons.ts +0 -4
- package/src/scripts/saveIconFiles.ts +0 -89
- package/src/styles.ts +0 -141
- package/src/theme.css +0 -168
- package/src/util/chip_colors.ts +0 -242
- package/src/util/cls.ts +0 -8
- package/src/util/debounce.ts +0 -28
- package/src/util/hash.ts +0 -11
- package/src/util/index.ts +0 -4
- package/src/util/key_to_icon_component.ts +0 -11
- package/src/util/lazy_chunk.ts +0 -101
- package/src/views/CardView.tsx +0 -281
- package/src/views/CollectionView/CollectionCardView.tsx +0 -265
- package/src/views/CollectionView/CollectionKanbanView.tsx +0 -246
- package/src/views/CollectionView/CollectionListView.tsx +0 -240
- package/src/views/CollectionView/CollectionTableView.tsx +0 -229
- package/src/views/CollectionView/CollectionView.tsx +0 -450
- package/src/views/CollectionView/CollectionViewToolbar.tsx +0 -242
- package/src/views/CollectionView/CollectionViewTypes.ts +0 -181
- package/src/views/CollectionView/DefaultCellRenderer.tsx +0 -404
- package/src/views/CollectionView/index.ts +0 -39
- package/src/views/CollectionView/resolveTitleProperty.ts +0 -52
- package/src/views/CollectionView/utils.ts +0 -14
- package/src/views/Kanban/Board.tsx +0 -384
- package/src/views/Kanban/BoardColumn.tsx +0 -138
- package/src/views/Kanban/BoardColumnTitle.tsx +0 -47
- package/src/views/Kanban/BoardSortableList.tsx +0 -182
- package/src/views/Kanban/board_types.ts +0 -80
- package/src/views/Kanban/index.tsx +0 -5
- package/src/views/Kanban/placement.ts +0 -62
- package/src/views/KanbanView.tsx +0 -32
- package/src/views/ListView.tsx +0 -296
- package/src/views/index.ts +0 -5
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
"use client";
|
|
3
|
-
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
|
|
4
|
-
import { iconSize } from "../icons/Icon";
|
|
5
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
6
|
-
import * as React from "react";
|
|
7
|
-
import { ChangeEvent, Children, useEffect, useState } from "react";
|
|
8
|
-
import { Command as CommandPrimitive } from "cmdk";
|
|
9
|
-
import { cls } from "../util";
|
|
10
|
-
|
|
11
|
-
import { Separator } from "./Separator";
|
|
12
|
-
import { Chip } from "./Chip";
|
|
13
|
-
import { SelectInputLabel } from "./common/SelectInputLabel";
|
|
14
|
-
import {
|
|
15
|
-
defaultBorderMixin,
|
|
16
|
-
fieldBackgroundDisabledMixin,
|
|
17
|
-
fieldBackgroundHoverMixin,
|
|
18
|
-
fieldBackgroundInvisibleMixin,
|
|
19
|
-
fieldBackgroundMixin,
|
|
20
|
-
focusedDisabled
|
|
21
|
-
} from "../styles";
|
|
22
|
-
import { useInjectStyles } from "../hooks";
|
|
23
|
-
import { usePortalContainer } from "../hooks/PortalContainerContext";
|
|
24
|
-
|
|
25
|
-
export type MultiSelectValue = string | number | boolean;
|
|
26
|
-
|
|
27
|
-
// Make the context properly generic
|
|
28
|
-
interface MultiSelectContextProps<T extends MultiSelectValue = string> {
|
|
29
|
-
fieldValue?: T[];
|
|
30
|
-
onItemClick: (v: T) => void;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Create a proper generic context
|
|
34
|
-
export const MultiSelectContext = React.createContext<MultiSelectContextProps<MultiSelectValue>>(null! as MultiSelectContextProps<MultiSelectValue>);
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Props for MultiSelect component
|
|
38
|
-
*/
|
|
39
|
-
interface MultiSelectProps<T extends MultiSelectValue = string> {
|
|
40
|
-
modalPopover?: boolean;
|
|
41
|
-
className?: string;
|
|
42
|
-
open?: boolean,
|
|
43
|
-
name?: string,
|
|
44
|
-
id?: string,
|
|
45
|
-
onOpenChange?: (open: boolean) => void,
|
|
46
|
-
value?: T[],
|
|
47
|
-
inputClassName?: string,
|
|
48
|
-
onChange?: React.EventHandler<ChangeEvent<HTMLSelectElement>>,
|
|
49
|
-
onValueChange?: (updatedValue: T[]) => void,
|
|
50
|
-
placeholder?: React.ReactNode,
|
|
51
|
-
size?: "smallest" | "small" | "medium" | "large",
|
|
52
|
-
useChips?: boolean,
|
|
53
|
-
label?: React.ReactNode | string,
|
|
54
|
-
disabled?: boolean,
|
|
55
|
-
error?: boolean,
|
|
56
|
-
position?: "item-aligned" | "popper",
|
|
57
|
-
endAdornment?: React.ReactNode,
|
|
58
|
-
multiple?: boolean,
|
|
59
|
-
includeSelectAll?: boolean,
|
|
60
|
-
includeClear?: boolean,
|
|
61
|
-
inputRef?: React.Ref<HTMLButtonElement>,
|
|
62
|
-
padding?: boolean,
|
|
63
|
-
invisible?: boolean,
|
|
64
|
-
children: React.ReactNode;
|
|
65
|
-
renderValues?: (values: T[]) => React.ReactNode;
|
|
66
|
-
portalContainer?: HTMLElement | null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Use generic type for the forwarded ref
|
|
70
|
-
export const MultiSelect = React.forwardRef<
|
|
71
|
-
HTMLButtonElement,
|
|
72
|
-
MultiSelectProps
|
|
73
|
-
>(
|
|
74
|
-
(
|
|
75
|
-
{
|
|
76
|
-
value,
|
|
77
|
-
size = "large",
|
|
78
|
-
label,
|
|
79
|
-
error,
|
|
80
|
-
onValueChange,
|
|
81
|
-
invisible,
|
|
82
|
-
disabled,
|
|
83
|
-
placeholder,
|
|
84
|
-
modalPopover = true,
|
|
85
|
-
includeClear = true,
|
|
86
|
-
includeSelectAll = true,
|
|
87
|
-
useChips = true,
|
|
88
|
-
className,
|
|
89
|
-
inputClassName,
|
|
90
|
-
inputRef,
|
|
91
|
-
children,
|
|
92
|
-
renderValues,
|
|
93
|
-
open,
|
|
94
|
-
onOpenChange,
|
|
95
|
-
portalContainer
|
|
96
|
-
},
|
|
97
|
-
ref
|
|
98
|
-
) => {
|
|
99
|
-
const [isMounted, setIsMounted] = useState(false);
|
|
100
|
-
const [isPopoverOpen, setIsPopoverOpen] = useState(open ?? false);
|
|
101
|
-
const [selectedValues, setSelectedValues] = useState<string[]>(value ?? []);
|
|
102
|
-
|
|
103
|
-
// Get the portal container from context
|
|
104
|
-
const contextContainer = usePortalContainer();
|
|
105
|
-
|
|
106
|
-
// Prioritize manual prop, fallback to context container
|
|
107
|
-
const finalContainer = (portalContainer ?? contextContainer ?? undefined) as HTMLElement | undefined;
|
|
108
|
-
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
setIsMounted(true);
|
|
111
|
-
}, []);
|
|
112
|
-
|
|
113
|
-
const onPopoverOpenChange = (open: boolean) => {
|
|
114
|
-
setIsPopoverOpen(open);
|
|
115
|
-
onOpenChange?.(open);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
setIsPopoverOpen(open ?? false);
|
|
120
|
-
}, [open]);
|
|
121
|
-
|
|
122
|
-
const allValues = React.useMemo(() => children
|
|
123
|
-
?
|
|
124
|
-
Children.map(children, (child) => {
|
|
125
|
-
if (React.isValidElement<MultiSelectItemProps>(child)) {
|
|
126
|
-
return child.props.value;
|
|
127
|
-
}
|
|
128
|
-
return null;
|
|
129
|
-
})?.filter(Boolean) ?? []
|
|
130
|
-
: [], [children]);
|
|
131
|
-
|
|
132
|
-
const optionsMap = React.useMemo(() => {
|
|
133
|
-
const map = new Map<string, React.ReactNode>();
|
|
134
|
-
Children.forEach(children, (child) => {
|
|
135
|
-
if (React.isValidElement<MultiSelectItemProps>(child)) {
|
|
136
|
-
map.set(String(child.props.value), child.props.children);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
return map;
|
|
140
|
-
}, [children]);
|
|
141
|
-
|
|
142
|
-
React.useEffect(() => {
|
|
143
|
-
setSelectedValues(value ?? []);
|
|
144
|
-
}, [value]);
|
|
145
|
-
|
|
146
|
-
const updateValues = React.useCallback((values: string[]) => {
|
|
147
|
-
setSelectedValues(values);
|
|
148
|
-
onValueChange?.(values);
|
|
149
|
-
}, [onValueChange]);
|
|
150
|
-
|
|
151
|
-
const onItemClick = React.useCallback((newValue: MultiSelectValue) => {
|
|
152
|
-
let newSelectedValues: string[];
|
|
153
|
-
if (selectedValues.some(v => String(v) === String(newValue))) {
|
|
154
|
-
newSelectedValues = selectedValues.filter(v => String(v) !== String(newValue));
|
|
155
|
-
} else {
|
|
156
|
-
newSelectedValues = [...selectedValues, String(newValue)];
|
|
157
|
-
}
|
|
158
|
-
updateValues(newSelectedValues);
|
|
159
|
-
}, [selectedValues, updateValues]);
|
|
160
|
-
|
|
161
|
-
const handleInputKeyDown = (
|
|
162
|
-
event: React.KeyboardEvent<HTMLInputElement>
|
|
163
|
-
) => {
|
|
164
|
-
if (event.key === "Enter") {
|
|
165
|
-
onPopoverOpenChange(true);
|
|
166
|
-
} else if (event.key === "Backspace" && !event.currentTarget.value) {
|
|
167
|
-
const newSelectedValues = [...selectedValues];
|
|
168
|
-
newSelectedValues.pop();
|
|
169
|
-
updateValues(newSelectedValues);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
const toggleOption = (value: string) => {
|
|
174
|
-
const newSelectedValues = selectedValues.some(v => String(v) === String(value))
|
|
175
|
-
? selectedValues.filter(v => String(v) !== String(value))
|
|
176
|
-
: [...selectedValues, value];
|
|
177
|
-
updateValues(newSelectedValues);
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const handleClear = () => {
|
|
181
|
-
updateValues([]);
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const handleTogglePopover = () => {
|
|
185
|
-
onPopoverOpenChange(!isPopoverOpen);
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
const toggleAll = () => {
|
|
189
|
-
if (selectedValues.length === allValues.length) {
|
|
190
|
-
handleClear();
|
|
191
|
-
} else {
|
|
192
|
-
updateValues(allValues);
|
|
193
|
-
}
|
|
194
|
-
onPopoverOpenChange(false);
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// Scoped to this popover. Unscoped, it reached every other cmdk list on
|
|
198
|
-
// the page — the relation and user selectors set their own height on
|
|
199
|
-
// the list and got a second, competing scroll container inside it.
|
|
200
|
-
useInjectStyles("MultiSelect", `
|
|
201
|
-
[data-multi-select-content] [cmdk-group] {
|
|
202
|
-
max-height: 45vh;
|
|
203
|
-
overflow-y: auto;
|
|
204
|
-
} `)
|
|
205
|
-
|
|
206
|
-
const contextValue = React.useMemo(() => ({
|
|
207
|
-
fieldValue: selectedValues,
|
|
208
|
-
onItemClick
|
|
209
|
-
}), [selectedValues, onItemClick]);
|
|
210
|
-
|
|
211
|
-
return (
|
|
212
|
-
<MultiSelectContext.Provider value={contextValue}>
|
|
213
|
-
|
|
214
|
-
{typeof label === "string" ? <SelectInputLabel error={error}>{label}</SelectInputLabel> : label}
|
|
215
|
-
|
|
216
|
-
<PopoverPrimitive.Root
|
|
217
|
-
open={isMounted && isPopoverOpen}
|
|
218
|
-
onOpenChange={onPopoverOpenChange}
|
|
219
|
-
modal={modalPopover}
|
|
220
|
-
>
|
|
221
|
-
<PopoverPrimitive.Trigger asChild>
|
|
222
|
-
<button
|
|
223
|
-
ref={inputRef ?? ref}
|
|
224
|
-
onClick={handleTogglePopover}
|
|
225
|
-
className={cls(
|
|
226
|
-
{
|
|
227
|
-
"min-h-[28px]": size === "smallest",
|
|
228
|
-
"min-h-[32px]": size === "small",
|
|
229
|
-
"min-h-[40px]": size === "medium",
|
|
230
|
-
"min-h-[48px]": size === "large"
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
// Kept tight so the min-height above governs:
|
|
234
|
-
// py-2 plus a medium Chip overflowed it and made
|
|
235
|
-
// smallest/small render at the same height.
|
|
236
|
-
"py-0": size === "smallest",
|
|
237
|
-
"py-0.5": size === "small",
|
|
238
|
-
"py-1": size === "medium" || size === "large"
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
"px-2": size === "small" || size === "smallest",
|
|
242
|
-
"px-4": size === "medium" || size === "large"
|
|
243
|
-
},
|
|
244
|
-
"select-none rounded-lg text-sm",
|
|
245
|
-
"focus:ring-0 focus-visible:ring-0 outline-none focus:outline-none focus-visible:outline-none",
|
|
246
|
-
invisible ? fieldBackgroundInvisibleMixin : fieldBackgroundMixin,
|
|
247
|
-
disabled ? fieldBackgroundDisabledMixin : fieldBackgroundHoverMixin,
|
|
248
|
-
"relative flex items-center",
|
|
249
|
-
className,
|
|
250
|
-
inputClassName
|
|
251
|
-
)}
|
|
252
|
-
>
|
|
253
|
-
{selectedValues.length > 0 ? (
|
|
254
|
-
<div className="flex justify-between items-center w-full">
|
|
255
|
-
<div className="flex flex-wrap items-center gap-1.5 text-start">
|
|
256
|
-
{renderValues && renderValues(selectedValues)}
|
|
257
|
-
{!renderValues && selectedValues.map((value) => {
|
|
258
|
-
|
|
259
|
-
const optionChildren = optionsMap.get(String(value));
|
|
260
|
-
if (!useChips) {
|
|
261
|
-
return optionChildren;
|
|
262
|
-
}
|
|
263
|
-
return (
|
|
264
|
-
<Chip
|
|
265
|
-
size={size === "smallest" || size === "small" ? "smallest" : "small"}
|
|
266
|
-
key={String(value)}
|
|
267
|
-
className={cls("flex flex-row items-center p-1")}
|
|
268
|
-
>
|
|
269
|
-
{optionChildren}
|
|
270
|
-
<XIcon
|
|
271
|
-
size={iconSize.smallest}
|
|
272
|
-
onClick={(event) => {
|
|
273
|
-
event.stopPropagation();
|
|
274
|
-
toggleOption(value);
|
|
275
|
-
}}
|
|
276
|
-
/>
|
|
277
|
-
</Chip>
|
|
278
|
-
);
|
|
279
|
-
})}
|
|
280
|
-
</div>
|
|
281
|
-
<div className="flex items-center justify-between">
|
|
282
|
-
{includeClear && <XIcon
|
|
283
|
-
className={"ml-4"}
|
|
284
|
-
size={iconSize.small}
|
|
285
|
-
onClick={(event) => {
|
|
286
|
-
event.stopPropagation();
|
|
287
|
-
handleClear();
|
|
288
|
-
}}
|
|
289
|
-
/>}
|
|
290
|
-
<div className={cls("px-2 h-full flex items-center")}>
|
|
291
|
-
<ChevronDownIcon size={size === "large" ? iconSize.medium : iconSize.small}
|
|
292
|
-
className={cls("transition", isPopoverOpen ? "rotate-180" : "")}/>
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
</div>
|
|
296
|
-
) : (
|
|
297
|
-
<div className="flex items-center justify-between w-full mx-auto">
|
|
298
|
-
<span className="text-sm">
|
|
299
|
-
{placeholder}
|
|
300
|
-
</span>
|
|
301
|
-
<div className={cls("px-2 h-full flex items-center")}>
|
|
302
|
-
<ChevronDownIcon size={size === "large" ? iconSize.medium : iconSize.small}
|
|
303
|
-
className={cls("transition", isPopoverOpen ? "rotate-180" : "")}/>
|
|
304
|
-
</div>
|
|
305
|
-
</div>
|
|
306
|
-
)}
|
|
307
|
-
</button>
|
|
308
|
-
</PopoverPrimitive.Trigger>
|
|
309
|
-
<PopoverPrimitive.Portal container={finalContainer}>
|
|
310
|
-
<PopoverPrimitive.Content
|
|
311
|
-
data-multi-select-content
|
|
312
|
-
className={cls("z-50 overflow-hidden border bg-white dark:bg-surface-800 rounded-lg w-[400px]", defaultBorderMixin)}
|
|
313
|
-
align="start"
|
|
314
|
-
sideOffset={8}
|
|
315
|
-
onEscapeKeyDown={() => onPopoverOpenChange(false)}
|
|
316
|
-
>
|
|
317
|
-
<CommandPrimitive>
|
|
318
|
-
<div className={"flex flex-row items-center"}>
|
|
319
|
-
<CommandPrimitive.Input
|
|
320
|
-
className={cls(focusedDisabled, "bg-transparent outline-none flex-1 h-full w-full m-4 flex-grow text-surface-accent-900 dark:text-white")}
|
|
321
|
-
placeholder="Search..."
|
|
322
|
-
onKeyDown={handleInputKeyDown}
|
|
323
|
-
/>
|
|
324
|
-
{selectedValues.length > 0 && (
|
|
325
|
-
<div
|
|
326
|
-
onClick={handleClear}
|
|
327
|
-
className="text-sm justify-center cursor-pointer py-3 px-4 text-text-secondary dark:text-text-secondary-dark">
|
|
328
|
-
Clear
|
|
329
|
-
</div>
|
|
330
|
-
)}
|
|
331
|
-
</div>
|
|
332
|
-
<Separator orientation={"horizontal"} className={"my-0"}/>
|
|
333
|
-
<CommandPrimitive.List>
|
|
334
|
-
<CommandPrimitive.Empty className={"px-4 py-2 text-sm text-text-secondary dark:text-text-secondary-dark"}>
|
|
335
|
-
No results found.
|
|
336
|
-
</CommandPrimitive.Empty>
|
|
337
|
-
<CommandPrimitive.Group>
|
|
338
|
-
{includeSelectAll && <CommandPrimitive.Item
|
|
339
|
-
key="all"
|
|
340
|
-
onSelect={toggleAll}
|
|
341
|
-
className={
|
|
342
|
-
cls(
|
|
343
|
-
"flex flex-row items-center gap-1.5",
|
|
344
|
-
"cursor-pointer",
|
|
345
|
-
"m-1",
|
|
346
|
-
"ring-offset-transparent",
|
|
347
|
-
"p-1 rounded-md aria-[selected=true]:outline-none aria-[selected=true]:ring-2 aria-[selected=true]:ring-primary aria-[selected=true]:ring-opacity-75 aria-[selected=true]:ring-primary/75 aria-[selected=true]:ring-offset-2",
|
|
348
|
-
"aria-[selected=true]:bg-surface-accent-100 aria-[selected=true]:dark:bg-surface-accent-900",
|
|
349
|
-
"cursor-pointer p-2 rounded-md aria-[selected=true]:bg-surface-accent-100 aria-[selected=true]:dark:bg-surface-accent-900"
|
|
350
|
-
)
|
|
351
|
-
}
|
|
352
|
-
>
|
|
353
|
-
<InnerCheckBox checked={selectedValues.length === allValues.length}/>
|
|
354
|
-
<span className={"text-sm text-text-secondary dark:text-text-secondary-dark"}>(Select All)</span>
|
|
355
|
-
</CommandPrimitive.Item>}
|
|
356
|
-
{children}
|
|
357
|
-
</CommandPrimitive.Group>
|
|
358
|
-
</CommandPrimitive.List>
|
|
359
|
-
</CommandPrimitive>
|
|
360
|
-
</PopoverPrimitive.Content>
|
|
361
|
-
</PopoverPrimitive.Portal>
|
|
362
|
-
</PopoverPrimitive.Root>
|
|
363
|
-
</MultiSelectContext.Provider>
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
MultiSelect.displayName = "MultiSelect";
|
|
369
|
-
|
|
370
|
-
export interface MultiSelectItemProps<T extends MultiSelectValue = string> {
|
|
371
|
-
value: T;
|
|
372
|
-
children?: React.ReactNode,
|
|
373
|
-
className?: string;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export const MultiSelectItem = React.memo(function MultiSelectItem<T extends MultiSelectValue = string>({
|
|
377
|
-
children,
|
|
378
|
-
value,
|
|
379
|
-
className
|
|
380
|
-
}: MultiSelectItemProps<T>) {
|
|
381
|
-
const context = React.useContext(MultiSelectContext);
|
|
382
|
-
if (!context) throw new Error("MultiSelectItem must be used inside a MultiSelect");
|
|
383
|
-
const {
|
|
384
|
-
fieldValue,
|
|
385
|
-
onItemClick
|
|
386
|
-
} = context;
|
|
387
|
-
|
|
388
|
-
const isSelected = (fieldValue ?? []).some(v => String(v) === String(value));
|
|
389
|
-
|
|
390
|
-
return <CommandPrimitive.Item
|
|
391
|
-
onMouseDown={(e) => {
|
|
392
|
-
e.preventDefault();
|
|
393
|
-
e.stopPropagation();
|
|
394
|
-
}}
|
|
395
|
-
onSelect={(_) => {
|
|
396
|
-
onItemClick(value);
|
|
397
|
-
}}
|
|
398
|
-
className={cls(
|
|
399
|
-
"flex flex-row items-center gap-1.5",
|
|
400
|
-
isSelected ? "bg-surface-accent-200 dark:bg-surface-accent-950" : "",
|
|
401
|
-
"cursor-pointer",
|
|
402
|
-
"m-1",
|
|
403
|
-
"ring-offset-transparent",
|
|
404
|
-
"p-1 rounded-md aria-[selected=true]:outline-none aria-[selected=true]:ring-2 aria-[selected=true]:ring-primary aria-[selected=true]:ring-opacity-75 aria-[selected=true]:ring-primary/75 aria-[selected=true]:ring-offset-2",
|
|
405
|
-
"aria-[selected=true]:bg-surface-accent-100 aria-[selected=true]:dark:bg-surface-accent-900",
|
|
406
|
-
"cursor-pointer p-2 rounded-md aria-[selected=true]:bg-surface-accent-100 aria-[selected=true]:dark:bg-surface-accent-900",
|
|
407
|
-
"text-surface-accent-700 dark:text-surface-accent-300",
|
|
408
|
-
className
|
|
409
|
-
)}
|
|
410
|
-
>
|
|
411
|
-
<InnerCheckBox checked={isSelected}/>
|
|
412
|
-
{children}
|
|
413
|
-
</CommandPrimitive.Item>;
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
const InnerCheckBox = React.memo(function InnerCheckBox({ checked }: { checked: boolean }) {
|
|
417
|
-
return <div className={cls(
|
|
418
|
-
"p-2",
|
|
419
|
-
"w-8 h-8",
|
|
420
|
-
"inline-flex items-center justify-center text-sm font-medium focus:outline-none transition-colors ease-in-out duration-150"
|
|
421
|
-
)}>
|
|
422
|
-
<div
|
|
423
|
-
className={cls(
|
|
424
|
-
"border-2 relative transition-colors ease-in-out duration-150",
|
|
425
|
-
"w-4 h-4 rounded-sm flex items-center justify-center",
|
|
426
|
-
(checked ? "bg-primary" : "bg-white dark:bg-surface-accent-900"),
|
|
427
|
-
(checked) ? "text-surface-accent-100 dark:text-surface-accent-900" : "",
|
|
428
|
-
(checked ? "border-transparent" : "border-surface-accent-800 dark:border-surface-accent-200")
|
|
429
|
-
)}>
|
|
430
|
-
{checked && <CheckIcon size={iconSize.smallest} className={"absolute"}/>}
|
|
431
|
-
</div>
|
|
432
|
-
</div>
|
|
433
|
-
});
|
package/src/components/Paper.tsx
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import { paperMixin } from "../styles";
|
|
4
|
-
import { cls } from "../util";
|
|
5
|
-
|
|
6
|
-
export function Paper({
|
|
7
|
-
children,
|
|
8
|
-
style,
|
|
9
|
-
className
|
|
10
|
-
}: {
|
|
11
|
-
children: React.ReactNode;
|
|
12
|
-
style?: React.CSSProperties;
|
|
13
|
-
className?: string;
|
|
14
|
-
|
|
15
|
-
}) {
|
|
16
|
-
return (
|
|
17
|
-
<div
|
|
18
|
-
className={cls(paperMixin, className)}
|
|
19
|
-
style={style}>
|
|
20
|
-
{children}
|
|
21
|
-
</div>
|
|
22
|
-
)
|
|
23
|
-
}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
|
-
|
|
5
|
-
import { paperMixin } from "../styles";
|
|
6
|
-
import { cls } from "../util";
|
|
7
|
-
import { useInjectStyles } from "../hooks";
|
|
8
|
-
import { usePortalContainer } from "../hooks/PortalContainerContext";
|
|
9
|
-
|
|
10
|
-
export type PopoverSide = "top" | "right" | "bottom" | "left";
|
|
11
|
-
export type PopoverAlign = "start" | "center" | "end";
|
|
12
|
-
|
|
13
|
-
export interface PopoverProps {
|
|
14
|
-
trigger: React.ReactNode;
|
|
15
|
-
children: React.ReactNode;
|
|
16
|
-
open?: boolean;
|
|
17
|
-
onOpenChange?: (open: boolean) => void;
|
|
18
|
-
side?: PopoverSide;
|
|
19
|
-
sideOffset?: number;
|
|
20
|
-
align?: PopoverAlign;
|
|
21
|
-
alignOffset?: number;
|
|
22
|
-
arrowPadding?: number;
|
|
23
|
-
sticky?: "partial" | "always";
|
|
24
|
-
hideWhenDetached?: boolean;
|
|
25
|
-
avoidCollisions?: boolean;
|
|
26
|
-
enabled?: boolean;
|
|
27
|
-
modal?: boolean;
|
|
28
|
-
className?: string;
|
|
29
|
-
portalContainer?: HTMLElement | null;
|
|
30
|
-
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
|
|
31
|
-
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function Popover({
|
|
35
|
-
trigger,
|
|
36
|
-
children,
|
|
37
|
-
open,
|
|
38
|
-
onOpenChange,
|
|
39
|
-
side,
|
|
40
|
-
sideOffset = 5,
|
|
41
|
-
align,
|
|
42
|
-
alignOffset,
|
|
43
|
-
arrowPadding,
|
|
44
|
-
sticky,
|
|
45
|
-
hideWhenDetached,
|
|
46
|
-
avoidCollisions,
|
|
47
|
-
enabled = true,
|
|
48
|
-
modal = false,
|
|
49
|
-
portalContainer,
|
|
50
|
-
className,
|
|
51
|
-
onMouseEnter,
|
|
52
|
-
onMouseLeave
|
|
53
|
-
}: PopoverProps) {
|
|
54
|
-
|
|
55
|
-
useInjectStyles("Popover", popoverStyles);
|
|
56
|
-
|
|
57
|
-
// Get the portal container from context
|
|
58
|
-
const contextContainer = usePortalContainer();
|
|
59
|
-
|
|
60
|
-
// Prioritize manual prop, fallback to context container
|
|
61
|
-
const finalContainer = (portalContainer ?? contextContainer ?? undefined) as HTMLElement | undefined;
|
|
62
|
-
|
|
63
|
-
if (!enabled)
|
|
64
|
-
return <>{trigger}</>;
|
|
65
|
-
|
|
66
|
-
return <PopoverPrimitive.Root open={open}
|
|
67
|
-
onOpenChange={onOpenChange}
|
|
68
|
-
modal={modal}>
|
|
69
|
-
|
|
70
|
-
<PopoverPrimitive.Trigger asChild>
|
|
71
|
-
{trigger}
|
|
72
|
-
</PopoverPrimitive.Trigger>
|
|
73
|
-
|
|
74
|
-
<PopoverPrimitive.Portal container={finalContainer}>
|
|
75
|
-
<PopoverPrimitive.Content
|
|
76
|
-
// `z-50`, the floating layer — see the note in `Menu`. Below it
|
|
77
|
-
// a popover opened from inside a dialog or a side panel is
|
|
78
|
-
// painted under the thing that owns its trigger.
|
|
79
|
-
className={cls(paperMixin,
|
|
80
|
-
"PopoverContent z-50", className)}
|
|
81
|
-
side={side}
|
|
82
|
-
sideOffset={sideOffset}
|
|
83
|
-
align={align}
|
|
84
|
-
alignOffset={alignOffset}
|
|
85
|
-
arrowPadding={arrowPadding}
|
|
86
|
-
sticky={sticky}
|
|
87
|
-
hideWhenDetached={hideWhenDetached}
|
|
88
|
-
avoidCollisions={avoidCollisions}
|
|
89
|
-
onMouseEnter={onMouseEnter}
|
|
90
|
-
onMouseLeave={onMouseLeave}>
|
|
91
|
-
|
|
92
|
-
{children}
|
|
93
|
-
<PopoverPrimitive.Arrow className="fill-white dark:fill-surface-900"/>
|
|
94
|
-
</PopoverPrimitive.Content>
|
|
95
|
-
</PopoverPrimitive.Portal>
|
|
96
|
-
</PopoverPrimitive.Root>;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const popoverStyles = `
|
|
100
|
-
/* ... (styles remain unchanged) ... */
|
|
101
|
-
.PopoverContent {
|
|
102
|
-
animation-duration: 400ms;
|
|
103
|
-
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
104
|
-
will-change: transform, opacity;
|
|
105
|
-
}
|
|
106
|
-
.PopoverContent[data-state='open'][data-side='top'] {
|
|
107
|
-
animation-name: slideDownAndFade;
|
|
108
|
-
}
|
|
109
|
-
.PopoverContent[data-state='open'][data-side='right'] {
|
|
110
|
-
animation-name: slideLeftAndFade;
|
|
111
|
-
}
|
|
112
|
-
.PopoverContent[data-state='open'][data-side='bottom'] {
|
|
113
|
-
animation-name: slideUpAndFade;
|
|
114
|
-
}
|
|
115
|
-
.PopoverContent[data-state='open'][data-side='left'] {
|
|
116
|
-
animation-name: slideRightAndFade;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@keyframes slideUpAndFade {
|
|
120
|
-
from {
|
|
121
|
-
opacity: 0;
|
|
122
|
-
transform: translateY(2px);
|
|
123
|
-
}
|
|
124
|
-
to {
|
|
125
|
-
opacity: 1;
|
|
126
|
-
transform: translateY(0);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
@keyframes slideRightAndFade {
|
|
131
|
-
from {
|
|
132
|
-
opacity: 0;
|
|
133
|
-
transform: translateX(-2px);
|
|
134
|
-
}
|
|
135
|
-
to {
|
|
136
|
-
opacity: 1;
|
|
137
|
-
transform: translateX(0);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
@keyframes slideDownAndFade {
|
|
142
|
-
from {
|
|
143
|
-
opacity: 0;
|
|
144
|
-
transform: translateY(-2px);
|
|
145
|
-
}
|
|
146
|
-
to {
|
|
147
|
-
opacity: 1;
|
|
148
|
-
transform: translateY(0);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@keyframes slideLeftAndFade {
|
|
153
|
-
from {
|
|
154
|
-
opacity: 0;
|
|
155
|
-
transform: translateX(2px);
|
|
156
|
-
}
|
|
157
|
-
to {
|
|
158
|
-
opacity: 1;
|
|
159
|
-
transform: translateX(0);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
`;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import * as React from "react"
|
|
3
|
-
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
|
4
|
-
import { cls } from "../util";
|
|
5
|
-
|
|
6
|
-
export interface RadioGroupProps {
|
|
7
|
-
id?: string;
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
name?: string
|
|
10
|
-
required?: boolean;
|
|
11
|
-
disabled?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* Whether keyboard navigation should loop around
|
|
14
|
-
* @defaultValue false
|
|
15
|
-
*/
|
|
16
|
-
loop?: boolean;
|
|
17
|
-
defaultValue?: string;
|
|
18
|
-
value?: string;
|
|
19
|
-
|
|
20
|
-
onValueChange?(value: string): void;
|
|
21
|
-
|
|
22
|
-
className?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const RadioGroup = React.forwardRef<
|
|
26
|
-
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
|
27
|
-
RadioGroupProps
|
|
28
|
-
>(({
|
|
29
|
-
className,
|
|
30
|
-
...props
|
|
31
|
-
}, ref) => {
|
|
32
|
-
return (
|
|
33
|
-
<RadioGroupPrimitive.Root
|
|
34
|
-
className={cls("grid gap-2", className)}
|
|
35
|
-
{...props}
|
|
36
|
-
ref={ref}
|
|
37
|
-
/>
|
|
38
|
-
)
|
|
39
|
-
})
|
|
40
|
-
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
|
41
|
-
|
|
42
|
-
export interface RadioGroupItemProps {
|
|
43
|
-
id?: string;
|
|
44
|
-
value: string;
|
|
45
|
-
checked?: boolean;
|
|
46
|
-
required?: boolean;
|
|
47
|
-
className?: string;
|
|
48
|
-
disabled?: boolean;
|
|
49
|
-
}
|
|
50
|
-
const RadioGroupItem = React.forwardRef<
|
|
51
|
-
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
|
52
|
-
RadioGroupItemProps
|
|
53
|
-
>(({
|
|
54
|
-
className,
|
|
55
|
-
...props
|
|
56
|
-
}, ref) => {
|
|
57
|
-
return (
|
|
58
|
-
<RadioGroupPrimitive.Item
|
|
59
|
-
ref={ref}
|
|
60
|
-
className={cls(
|
|
61
|
-
"aspect-square h-4 w-4 rounded-full border border-primary text-primary focus:outline-hidden focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
62
|
-
className
|
|
63
|
-
)}
|
|
64
|
-
{...props}
|
|
65
|
-
>
|
|
66
|
-
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
|
67
|
-
<div className="h-2.5 w-2.5 fill-current text-current bg-primary rounded-full"/>
|
|
68
|
-
</RadioGroupPrimitive.Indicator>
|
|
69
|
-
</RadioGroupPrimitive.Item>
|
|
70
|
-
)
|
|
71
|
-
})
|
|
72
|
-
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
|
73
|
-
|
|
74
|
-
export { RadioGroup, RadioGroupItem }
|