@rebasepro/ui 0.17.3 → 0.18.0

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 (127) hide show
  1. package/README.md +4 -0
  2. package/dist/components/MultiSelect.d.ts +10 -0
  3. package/dist/index.es.js +2 -1
  4. package/dist/index.es.js.map +1 -1
  5. package/package.json +32 -23
  6. package/src/components/Alert.tsx +0 -118
  7. package/src/components/Autocomplete.tsx +0 -93
  8. package/src/components/Avatar.tsx +0 -73
  9. package/src/components/Badge.tsx +0 -44
  10. package/src/components/BooleanSwitch.tsx +0 -116
  11. package/src/components/BooleanSwitchWithLabel.tsx +0 -120
  12. package/src/components/Button.tsx +0 -110
  13. package/src/components/Card.tsx +0 -43
  14. package/src/components/CenteredView.tsx +0 -35
  15. package/src/components/Checkbox.tsx +0 -129
  16. package/src/components/Chip.tsx +0 -131
  17. package/src/components/CircularProgress.tsx +0 -53
  18. package/src/components/CircularProgressCenter.tsx +0 -27
  19. package/src/components/Collapse.tsx +0 -66
  20. package/src/components/ColorPicker.tsx +0 -140
  21. package/src/components/Container.tsx +0 -51
  22. package/src/components/DateTimeField.tsx +0 -363
  23. package/src/components/DebouncedTextField.tsx +0 -76
  24. package/src/components/Dialog.tsx +0 -159
  25. package/src/components/DialogActions.tsx +0 -29
  26. package/src/components/DialogContent.tsx +0 -27
  27. package/src/components/DialogTitle.tsx +0 -41
  28. package/src/components/ErrorBoundary.tsx +0 -236
  29. package/src/components/ExpandablePanel.tsx +0 -130
  30. package/src/components/FileUpload.tsx +0 -103
  31. package/src/components/FilterChip.tsx +0 -89
  32. package/src/components/IconButton.tsx +0 -101
  33. package/src/components/InfoLabel.tsx +0 -23
  34. package/src/components/InputLabel.tsx +0 -40
  35. package/src/components/Label.tsx +0 -32
  36. package/src/components/LoadingButton.tsx +0 -32
  37. package/src/components/Markdown.tsx +0 -55
  38. package/src/components/Menu.tsx +0 -114
  39. package/src/components/Menubar.tsx +0 -355
  40. package/src/components/MultiSelect.tsx +0 -433
  41. package/src/components/Paper.tsx +0 -23
  42. package/src/components/Popover.tsx +0 -162
  43. package/src/components/RadioGroup.tsx +0 -74
  44. package/src/components/ResizablePanels.tsx +0 -189
  45. package/src/components/SearchBar.tsx +0 -136
  46. package/src/components/Select.tsx +0 -326
  47. package/src/components/Separator.tsx +0 -28
  48. package/src/components/Sheet.tsx +0 -135
  49. package/src/components/Skeleton.tsx +0 -54
  50. package/src/components/Slider.tsx +0 -110
  51. package/src/components/Table.tsx +0 -178
  52. package/src/components/Tabs.tsx +0 -185
  53. package/src/components/TextField.tsx +0 -270
  54. package/src/components/TextareaAutosize.tsx +0 -368
  55. package/src/components/ToggleButtonGroup.tsx +0 -69
  56. package/src/components/Tooltip.tsx +0 -153
  57. package/src/components/Typography.tsx +0 -132
  58. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +0 -90
  59. package/src/components/VirtualTable/VirtualTable.tsx +0 -700
  60. package/src/components/VirtualTable/VirtualTableCell.tsx +0 -59
  61. package/src/components/VirtualTable/VirtualTableHeader.tsx +0 -327
  62. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +0 -250
  63. package/src/components/VirtualTable/VirtualTableProps.tsx +0 -339
  64. package/src/components/VirtualTable/VirtualTableRow.tsx +0 -51
  65. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +0 -44
  66. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -89
  67. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +0 -71
  68. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +0 -107
  69. package/src/components/VirtualTable/fields/VirtualTableSwitch.tsx +0 -28
  70. package/src/components/VirtualTable/index.tsx +0 -10
  71. package/src/components/VirtualTable/selection/SelectionContext.tsx +0 -36
  72. package/src/components/VirtualTable/selection/SelectionStore.ts +0 -54
  73. package/src/components/VirtualTable/types.tsx +0 -47
  74. package/src/components/common/SelectInputLabel.tsx +0 -23
  75. package/src/components/index.tsx +0 -62
  76. package/src/hooks/PortalContainerContext.tsx +0 -50
  77. package/src/hooks/index.ts +0 -7
  78. package/src/hooks/useDebounceCallback.tsx +0 -21
  79. package/src/hooks/useDebounceValue.tsx +0 -20
  80. package/src/hooks/useDebouncedCallback.ts +0 -39
  81. package/src/hooks/useInjectStyles.tsx +0 -31
  82. package/src/hooks/useOutsideAlerter.tsx +0 -46
  83. package/src/icons/GitHubIcon.tsx +0 -21
  84. package/src/icons/HandleIcon.tsx +0 -23
  85. package/src/icons/Icon.tsx +0 -33
  86. package/src/icons/LucideIconByName.tsx +0 -117
  87. package/src/icons/cool_icon_keys.ts +0 -12
  88. package/src/icons/icon_keys.ts +0 -1936
  89. package/src/icons/index.ts +0 -179
  90. package/src/index.css +0 -169
  91. package/src/index.ts +0 -47
  92. package/src/scripts/fixIconSizes.cjs +0 -92
  93. package/src/scripts/fixIconSizesToConst.cjs +0 -106
  94. package/src/scripts/generateIconKeys.ts +0 -41
  95. package/src/scripts/generateIcons.ts +0 -4
  96. package/src/scripts/saveIconFiles.ts +0 -89
  97. package/src/styles.ts +0 -141
  98. package/src/theme.css +0 -168
  99. package/src/util/chip_colors.ts +0 -242
  100. package/src/util/cls.ts +0 -8
  101. package/src/util/debounce.ts +0 -28
  102. package/src/util/hash.ts +0 -11
  103. package/src/util/index.ts +0 -4
  104. package/src/util/key_to_icon_component.ts +0 -11
  105. package/src/util/lazy_chunk.ts +0 -101
  106. package/src/views/CardView.tsx +0 -281
  107. package/src/views/CollectionView/CollectionCardView.tsx +0 -265
  108. package/src/views/CollectionView/CollectionKanbanView.tsx +0 -246
  109. package/src/views/CollectionView/CollectionListView.tsx +0 -240
  110. package/src/views/CollectionView/CollectionTableView.tsx +0 -229
  111. package/src/views/CollectionView/CollectionView.tsx +0 -450
  112. package/src/views/CollectionView/CollectionViewToolbar.tsx +0 -242
  113. package/src/views/CollectionView/CollectionViewTypes.ts +0 -181
  114. package/src/views/CollectionView/DefaultCellRenderer.tsx +0 -404
  115. package/src/views/CollectionView/index.ts +0 -39
  116. package/src/views/CollectionView/resolveTitleProperty.ts +0 -52
  117. package/src/views/CollectionView/utils.ts +0 -14
  118. package/src/views/Kanban/Board.tsx +0 -384
  119. package/src/views/Kanban/BoardColumn.tsx +0 -138
  120. package/src/views/Kanban/BoardColumnTitle.tsx +0 -47
  121. package/src/views/Kanban/BoardSortableList.tsx +0 -182
  122. package/src/views/Kanban/board_types.ts +0 -80
  123. package/src/views/Kanban/index.tsx +0 -5
  124. package/src/views/Kanban/placement.ts +0 -62
  125. package/src/views/KanbanView.tsx +0 -32
  126. package/src/views/ListView.tsx +0 -296
  127. package/src/views/index.ts +0 -5
@@ -1,159 +0,0 @@
1
- "use client";
2
- import React, { useEffect, useState } from "react";
3
- import * as DialogPrimitive from "@radix-ui/react-dialog";
4
- import { paperMixin } from "../styles";
5
- import { cls } from "../util";
6
- import { PortalContainerProvider, usePortalContainer } from "../hooks/PortalContainerContext";
7
-
8
- export type DialogProps = {
9
- open?: boolean;
10
- onOpenChange?: (open: boolean) => void;
11
- children: React.ReactNode;
12
- className?: string;
13
- containerClassName?: string;
14
- fullWidth?: boolean;
15
- fullHeight?: boolean;
16
- fullScreen?: boolean;
17
- scrollable?: boolean;
18
- maxWidth?: keyof typeof widthClasses;
19
- modal?: boolean;
20
- onOpenAutoFocus?: (e: Event) => void;
21
- onEscapeKeyDown?: (e: KeyboardEvent) => void;
22
- onPointerDownOutside?: (e: Event) => void;
23
- onInteractOutside?: (e: Event) => void;
24
- /**
25
- * If `true`, the dialog will not focus the first focusable element when opened.
26
- */
27
- disableInitialFocus?: boolean;
28
- portalContainer?: HTMLElement | null;
29
- "aria-describedby"?: string;
30
- };
31
-
32
- const widthClasses = {
33
- xs: "max-w-xs w-xs",
34
- sm: "max-w-sm w-sm",
35
- md: "max-w-md w-md",
36
- lg: "max-w-lg w-lg",
37
- xl: "max-w-xl w-xl",
38
- "2xl": "max-w-2xl w-2xl",
39
- "3xl": "max-w-3xl w-3xl",
40
- "4xl": "max-w-4xl w-4xl",
41
- "5xl": "max-w-5xl w-5xl",
42
- "6xl": "max-w-6xl w-6xl",
43
- "7xl": "max-w-7xl w-7xl",
44
- full: "max-w-full w-full"
45
- };
46
-
47
- export const Dialog = ({
48
- open,
49
- onOpenChange,
50
- children,
51
- className,
52
- containerClassName,
53
- fullWidth = true,
54
- fullHeight,
55
- fullScreen,
56
- scrollable = true,
57
- maxWidth = "lg",
58
- modal = true,
59
- onOpenAutoFocus,
60
- onEscapeKeyDown,
61
- onPointerDownOutside,
62
- onInteractOutside,
63
- disableInitialFocus = true,
64
- portalContainer,
65
- "aria-describedby": ariaDescribedby
66
- }: DialogProps) => {
67
- const [displayed, setDisplayed] = useState(false);
68
- // Where popups rendered *inside* this dialog get portaled to. A modal
69
- // dialog locks scrolling everywhere but its own content, so a popup
70
- // portaled to `document.body` renders fine and then refuses to scroll:
71
- // `react-remove-scroll` cancels every wheel event outside the lock.
72
- // Handing descendants this host keeps them inside it.
73
- const [popupHost, setPopupHost] = useState<HTMLDivElement | null>(null);
74
-
75
- // Get the portal container from context
76
- const contextContainer = usePortalContainer();
77
-
78
- // Prioritize manual prop, fallback to context container
79
- const finalContainer = (portalContainer ?? contextContainer ?? undefined) as HTMLElement | undefined;
80
-
81
- useEffect(() => {
82
- if (!open) {
83
- const timeout = setTimeout(() => {
84
- setDisplayed(false);
85
- }, 100);
86
- return () => clearTimeout(timeout);
87
- } else {
88
- setDisplayed(true);
89
- return () => {
90
- };
91
- }
92
- }, [open]);
93
-
94
- return (
95
- <DialogPrimitive.Root open={displayed || open}
96
- modal={modal}
97
- onOpenChange={onOpenChange}>
98
- <DialogPrimitive.Portal container={finalContainer}>
99
-
100
- <div className={cls("fixed inset-0 z-50", containerClassName)}>
101
-
102
- <DialogPrimitive.Overlay
103
- className={cls("fixed inset-0 transition-opacity ease-in-out duration-200 bg-black/50 dark:bg-black/60 backdrop-blur-sm",
104
- displayed && open ? "opacity-100" : "opacity-0",
105
- "z-50 fixed top-0 left-0 w-full h-full flex justify-center items-center"
106
- )}
107
- style={{
108
- pointerEvents: displayed ? "auto" : "none"
109
- }}
110
- />
111
-
112
- <DialogPrimitive.Content
113
- onEscapeKeyDown={onEscapeKeyDown}
114
- onOpenAutoFocus={(e) => {
115
- if (disableInitialFocus) {
116
- e.preventDefault();
117
- }
118
- onOpenAutoFocus?.(e);
119
- }}
120
- onPointerDownOutside={onPointerDownOutside}
121
- onInteractOutside={onInteractOutside}
122
- aria-describedby={ariaDescribedby}
123
- className={cls("relative h-full outline-none flex justify-center items-center z-60 opacity-100 transition-all duration-200 ease-in-out")}
124
- >
125
- <div
126
- className={cls(paperMixin,
127
- "rounded-2xl",
128
- "z-60",
129
- "relative",
130
- "overflow-hidden",
131
- "outline-none focus:outline-none",
132
- fullWidth && !fullScreen ? "w-11/12" : undefined,
133
- fullHeight && !fullScreen ? "h-full" : undefined,
134
- "text-text-primary dark:text-text-primary-dark",
135
- "justify-center items-center",
136
- fullScreen ? "h-screen w-screen" : "max-h-[90vh] shadow-lg",
137
- "ease-in-out duration-200",
138
- scrollable && "overflow-y-auto",
139
- displayed && open ? "opacity-100 scale-100" : "opacity-0 scale-[0.97]",
140
- maxWidth && !fullScreen ? widthClasses[maxWidth] : undefined,
141
- className
142
- )}>
143
- <PortalContainerProvider container={popupHost}>
144
- {children}
145
- </PortalContainerProvider>
146
- </div>
147
-
148
- {/* Sized to nothing so it changes no layout, but positioned and
149
- stacked above the paper so popups portaled here are not
150
- painted behind it. */}
151
- <div ref={setPopupHost} className={"relative z-70 w-0 h-0"}/>
152
-
153
- </DialogPrimitive.Content>
154
- </div>
155
-
156
- </DialogPrimitive.Portal>
157
- </DialogPrimitive.Root>
158
- );
159
- };
@@ -1,29 +0,0 @@
1
- import React from "react";
2
- import { defaultBorderMixin } from "../styles";
3
- import { cls } from "../util";
4
-
5
- export function DialogActions({
6
- children,
7
- position = "sticky",
8
- translucent = true,
9
- className
10
- }: {
11
- children: React.ReactNode,
12
- position?: "sticky" | "absolute",
13
- translucent?: boolean,
14
- className?: string
15
- }) {
16
-
17
- return <div
18
- className={cls(
19
- defaultBorderMixin,
20
- // `shrink-0`: as a flex child at the foot of a column this bar must
21
- // keep its height instead of being squeezed by the content above it.
22
- "pt-2 pb-4 px-4 border-t flex flex-row items-center justify-end shrink-0 bottom-0 right-0 left-0 text-right z-2 gap-2",
23
- position,
24
- "bg-white bg-opacity-60 bg-white/60 dark:bg-surface-800 dark:bg-opacity-60 dark:bg-surface-800/60",
25
- translucent ? "backdrop-blur-sm" : "",
26
- className)}>
27
- {children}
28
- </div>;
29
- }
@@ -1,27 +0,0 @@
1
- import React from "react";
2
- import { cls } from "../util";
3
-
4
- export function DialogContent({
5
- children,
6
- className,
7
- fullHeight,
8
- includeMargin = true
9
- }: {
10
- children: React.ReactNode,
11
- includeMargin?: boolean,
12
- fullHeight?: boolean,
13
- className?: string
14
- }) {
15
-
16
- if (fullHeight)
17
- return <div className={"flex-grow flex flex-col h-full relative"}>
18
- {children}
19
- </div>;
20
-
21
- return <div
22
- className={cls("flex-grow",
23
- { "my-8 mx-8": includeMargin },
24
- className)}>
25
- {children}
26
- </div>;
27
- }
@@ -1,41 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import * as DialogPrimitive from "@radix-ui/react-dialog";
5
- import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
6
- import { Typography, TypographyProps, TypographyVariant } from "./Typography";
7
- import { cls } from "../util";
8
-
9
- export type DialogContentProps = TypographyProps & {
10
- children: React.ReactNode,
11
- hidden?: boolean,
12
- className?: string,
13
- includeMargin?: boolean,
14
- variant?: TypographyVariant
15
- };
16
-
17
- export function DialogTitle({
18
- children,
19
- hidden,
20
- className,
21
- variant = "subtitle2",
22
- gutterBottom = true,
23
- includeMargin = true,
24
- ...props
25
- }: DialogContentProps) {
26
-
27
- const title = <DialogPrimitive.Title asChild>
28
- <Typography variant={variant}
29
- className={cls({ "mt-8 mx-8": includeMargin }, className)}
30
- gutterBottom={gutterBottom}
31
- {...props}>
32
- {children}
33
- </Typography>
34
- </DialogPrimitive.Title>;
35
-
36
- if (hidden) {
37
- return <VisuallyHidden.Root>{title}</VisuallyHidden.Root>
38
- }
39
-
40
- return title;
41
- }
@@ -1,236 +0,0 @@
1
-
2
- import React, { ErrorInfo, PropsWithChildren } from "react";
3
-
4
- import { AlertCircleIcon, ShieldAlertIcon, RefreshCwIcon, ArrowLeftIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
5
- import { iconSize } from "../icons/Icon";
6
- import { Typography } from "./Typography";
7
- import { Button } from "./Button";
8
- import { cls } from "../util";
9
- import { isChunkLoadError } from "../util/lazy_chunk";
10
-
11
- /**
12
- * The one error a user can fix themselves. A deploy replaces the hashed chunk
13
- * files, so a tab opened before it cannot load any lazy view it has not already
14
- * fetched — with the browser's raw message ("Failed to fetch dynamically
15
- * imported module: …") this reads as a broken build rather than a stale tab.
16
- */
17
- const CHUNK_ERROR_DESCRIPTION =
18
- "This app was updated while the tab was open, so part of it could not be loaded. Reload to continue.";
19
-
20
- /**
21
- * Checks whether the error message relates to missing permissions or
22
- * authorization failures. Used to show a friendlier message in fullPage mode.
23
- */
24
- function isPermissionError(error: Error | null): boolean {
25
- if (!error) return false;
26
- const msg = error.message?.toLowerCase() ?? "";
27
- const code = (error as { code?: string }).code?.toLowerCase() ?? "";
28
- return msg.includes("permission")
29
- || msg.includes("insufficient")
30
- || msg.includes("unauthorized")
31
- || msg.includes("forbidden")
32
- || msg.includes("access denied")
33
- || code === "permission_denied"
34
- || code === "insufficient_permissions"
35
- || (error as { status?: number }).status === 403;
36
- }
37
-
38
- export interface ErrorBoundaryProps {
39
- /**
40
- * When true, renders a full-page centered error screen instead of the
41
- * compact inline error. Intended for wrapping top-level app roots or
42
- * major route sections.
43
- */
44
- fullPage?: boolean;
45
- /**
46
- * Optional callback invoked when the user clicks "Try again". If provided,
47
- * the boundary resets its error state and calls this handler. If omitted,
48
- * the "Try again" button resets the boundary state, re-mounting children.
49
- */
50
- onReset?: () => void;
51
- }
52
-
53
- interface ErrorBoundaryState {
54
- error: Error | null;
55
- showDetails: boolean;
56
- }
57
-
58
- export class ErrorBoundary extends React.Component<PropsWithChildren<ErrorBoundaryProps>, ErrorBoundaryState> {
59
- constructor(props: PropsWithChildren<ErrorBoundaryProps>) {
60
- super(props);
61
- this.state = { error: null,
62
- showDetails: false };
63
- }
64
-
65
- static getDerivedStateFromError(error: Error) {
66
- return { error };
67
- }
68
-
69
- componentDidCatch(error: Error, _errorInfo: ErrorInfo) {
70
- console.error(error);
71
- }
72
-
73
- private handleReset = () => {
74
- this.setState({ error: null,
75
- showDetails: false });
76
- this.props.onReset?.();
77
- };
78
-
79
- private handleReload = () => {
80
- window.location.reload();
81
- };
82
-
83
- private toggleDetails = () => {
84
- this.setState(prev => ({ showDetails: !prev.showDetails }));
85
- };
86
-
87
- render() {
88
- if (this.state.error) {
89
- if (this.props.fullPage) {
90
- return this.renderFullPage();
91
- }
92
- return this.renderInline();
93
- }
94
-
95
- return this.props.children;
96
- }
97
-
98
- private renderInline() {
99
- const isStaleChunk = isChunkLoadError(this.state.error);
100
- return (
101
- <div className="flex flex-col m-2 items-start">
102
- <div className="flex items-center m-2">
103
- {isStaleChunk
104
- ? <RefreshCwIcon className={"text-text-secondary dark:text-text-secondary-dark"}
105
- size={iconSize.small}/>
106
- : <AlertCircleIcon className={"text-red-500 dark:text-red-400"} size={iconSize.small}/>}
107
- <div className="ml-4">{isStaleChunk ? "New version available" : "Error"}</div>
108
- </div>
109
- <Typography variant={"caption"}>
110
- {isStaleChunk
111
- ? CHUNK_ERROR_DESCRIPTION
112
- : this.state.error?.message ?? "See the error in the console"}
113
- </Typography>
114
- {isStaleChunk && <Button variant="outlined"
115
- color="neutral"
116
- size="small"
117
- className="mt-3 ml-2"
118
- onClick={this.handleReload}>
119
- <RefreshCwIcon size={16}/>
120
- Reload
121
- </Button>}
122
- </div>
123
- );
124
- }
125
-
126
- private renderFullPage() {
127
- const { error, showDetails } = this.state;
128
- const isPermission = isPermissionError(error);
129
- // Neither a fault nor a denial: the app is fine, this tab is behind it.
130
- const isStaleChunk = !isPermission && isChunkLoadError(error);
131
-
132
- const Icon = isPermission ? ShieldAlertIcon : isStaleChunk ? RefreshCwIcon : AlertCircleIcon;
133
- const title = isPermission
134
- ? "Access denied"
135
- : isStaleChunk
136
- ? "New version available"
137
- : "Something went wrong";
138
- const description = isPermission
139
- ? "You don't have permission to access this resource. Please check your account permissions or contact your administrator."
140
- : isStaleChunk
141
- ? CHUNK_ERROR_DESCRIPTION
142
- : "An unexpected error occurred. You can try reloading the page or going back.";
143
-
144
- return (
145
- <div className={cls(
146
- "flex items-center justify-center min-h-[400px] h-full w-full",
147
- "bg-surface-50 dark:bg-surface-950"
148
- )}>
149
- <div className="flex flex-col items-center max-w-md px-6 py-10 text-center">
150
- <div className={cls(
151
- "flex items-center justify-center w-14 h-14 rounded-xl mb-6",
152
- isPermission
153
- ? "bg-amber-100 dark:bg-amber-900/30"
154
- : isStaleChunk
155
- ? "bg-surface-100 dark:bg-surface-800"
156
- : "bg-red-100 dark:bg-red-900/30"
157
- )}>
158
- <Icon
159
- size={28}
160
- className={isPermission
161
- ? "text-amber-600 dark:text-amber-400"
162
- : isStaleChunk
163
- ? "text-text-secondary dark:text-text-secondary-dark"
164
- : "text-red-500 dark:text-red-400"}
165
- />
166
- </div>
167
-
168
- <Typography variant={"h6"}
169
- className="text-text-primary dark:text-text-primary-dark mb-2">
170
- {title}
171
- </Typography>
172
-
173
- <Typography variant={"body2"}
174
- className="text-text-secondary dark:text-text-secondary-dark mb-8">
175
- {description}
176
- </Typography>
177
-
178
- <div className="flex gap-3">
179
- {/* React caches a `lazy()` rejection: re-mounting the
180
- children re-throws without re-running the import, so
181
- "Try again" cannot recover a missing chunk. */}
182
- {!isStaleChunk && <Button
183
- variant="outlined"
184
- color="neutral"
185
- size="medium"
186
- onClick={this.handleReset}
187
- >
188
- <ArrowLeftIcon size={16}/>
189
- Try again
190
- </Button>}
191
- <Button
192
- variant="filled"
193
- color="primary"
194
- size="medium"
195
- onClick={this.handleReload}
196
- >
197
- <RefreshCwIcon size={16}/>
198
- Reload page
199
- </Button>
200
- </div>
201
-
202
- {/* For a stale chunk the message *is* the description
203
- above; repeating it under a disclosure adds nothing. */}
204
- {!isStaleChunk && error?.message && (
205
- <div className="mt-8 w-full">
206
- <button
207
- onClick={this.toggleDetails}
208
- className={cls(
209
- "flex items-center gap-1 mx-auto text-xs",
210
- "text-text-disabled dark:text-text-disabled-dark",
211
- "hover:text-text-secondary dark:hover:text-text-secondary-dark",
212
- "transition-colors cursor-pointer bg-transparent border-none p-0"
213
- )}
214
- >
215
- Technical details
216
- {showDetails
217
- ? <ChevronUpIcon size={14}/>
218
- : <ChevronDownIcon size={14}/>}
219
- </button>
220
- {showDetails && (
221
- <div className={cls(
222
- "mt-3 p-3 rounded-lg text-left text-xs",
223
- "bg-surface-100 dark:bg-surface-800/50",
224
- "text-text-secondary dark:text-text-secondary-dark",
225
- "font-mono break-all"
226
- )}>
227
- {error.message}
228
- </div>
229
- )}
230
- </div>
231
- )}
232
- </div>
233
- </div>
234
- );
235
- }
236
- }
@@ -1,130 +0,0 @@
1
-
2
- "use client";
3
- import React, { PropsWithChildren, useEffect, useState } from "react";
4
-
5
- import * as Collapsible from "@radix-ui/react-collapsible";
6
- import { defaultBorderMixin, fieldBackgroundMixin } from "../styles";
7
- import { ChevronDownIcon } from "lucide-react";
8
- import { cls } from "../util";
9
- import { useInjectStyles } from "../hooks";
10
-
11
- export function ExpandablePanel({
12
- title,
13
- children,
14
- invisible = false,
15
- expanded,
16
- onExpandedChange,
17
- initiallyExpanded = true,
18
- titleClassName,
19
- asField,
20
- className,
21
- innerClassName
22
- }: PropsWithChildren<{
23
- title: React.ReactNode,
24
- invisible?: boolean,
25
- initiallyExpanded?: boolean;
26
- expanded?: boolean;
27
- onExpandedChange?: (expanded: boolean) => void,
28
- titleClassName?: string,
29
- asField?: boolean,
30
- className?: string,
31
- innerClassName?: string
32
- }>) {
33
-
34
- useInjectStyles("ExpandablePanel", `
35
- .CollapsibleContent {
36
- overflow: hidden;
37
- }
38
- .CollapsibleContent[data-state='open'] {
39
- animation: slideDown 220ms ease-out
40
- }
41
- .CollapsibleContent[data-state='closed'] {
42
- animation: slideUp 220ms ease-out;
43
- }
44
-
45
- @keyframes slideDown {
46
- from {
47
- height: 0;
48
- }
49
- to {
50
- height: var(--radix-collapsible-content-height);
51
- }
52
- }
53
-
54
- @keyframes slideUp {
55
- from {
56
- height: var(--radix-collapsible-content-height);
57
- }
58
- to {
59
- height: 0;
60
- }
61
- }`);
62
-
63
- const [open, setOpen] = useState(expanded !== undefined ? expanded : initiallyExpanded);
64
- const [allowOverflow, setAllowOverflow] = useState(open);
65
-
66
- useEffect(() => {
67
- if (open) {
68
- setTimeout(() => {
69
- setAllowOverflow(true);
70
- }, 220);
71
- } else {
72
- setAllowOverflow(false);
73
- }
74
- }, [open]);
75
-
76
- useEffect(() => {
77
- if (expanded !== undefined)
78
- setOpen(expanded);
79
- }, [expanded]);
80
-
81
- return (<>
82
- <Collapsible.Root
83
- className={cls(
84
- !invisible && defaultBorderMixin + " border",
85
- "rounded-lg",
86
- "w-full",
87
- className
88
- )}
89
- open={open}
90
- onOpenChange={(updatedOpen: boolean) => {
91
- onExpandedChange?.(updatedOpen);
92
- setOpen(updatedOpen);
93
- }}>
94
-
95
- <Collapsible.Trigger asChild>
96
- <div
97
- className={cls(
98
- "rounded-t-lg flex items-center justify-between w-full min-h-[52px]",
99
- "hover:bg-surface-accent-200 hover:bg-opacity-40 hover:bg-surface-accent-200/40 dark:hover:bg-surface-800 dark:hover:bg-opacity-40 dark:hover:bg-surface-800/40 active:bg-surface-accent-300/50 dark:active:bg-surface-700/50",
100
- invisible ? "border-b px-2" : "p-4",
101
- open ? "py-6" : "py-4",
102
- "transition-all duration-200",
103
- invisible && defaultBorderMixin,
104
- asField && fieldBackgroundMixin,
105
- titleClassName,
106
- "cursor-pointer"
107
- )}
108
- role="button"
109
- tabIndex={0}
110
- aria-expanded={open}
111
- >
112
- {title}
113
- <ChevronDownIcon className={cls("transition", open ? "rotate-180" : "")}/>
114
- </div>
115
- </Collapsible.Trigger>
116
-
117
- <Collapsible.Content
118
- className={cls("CollapsibleContent")}
119
- style={{
120
- overflow: allowOverflow ? "visible" : "hidden"
121
- }}
122
- >
123
- <div className={innerClassName}>
124
- {children}
125
- </div>
126
- </Collapsible.Content>
127
- </Collapsible.Root>
128
- </>
129
- )
130
- }