@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,135 +0,0 @@
1
- "use client";
2
- import React, { useEffect, useState } from "react";
3
- import { cls } from "../util";
4
- import { defaultBorderMixin } from "../styles";
5
- import * as DialogPrimitive from "@radix-ui/react-dialog";
6
- import { usePortalContainer, PortalContainerProvider } from "../hooks/PortalContainerContext";
7
-
8
- interface SheetProps {
9
- children: React.ReactNode;
10
- open: boolean;
11
- title?: string;
12
- modal?: boolean;
13
- includeBackgroundOverlay?: boolean;
14
- side?: "top" | "bottom" | "left" | "right";
15
- darkBackground?: boolean;
16
- transparent?: boolean;
17
- onOpenChange?: (open: boolean) => void;
18
- onPointerDownOutside?: (e: Event) => void;
19
- onInteractOutside?: (e: Event) => void;
20
- className?: string;
21
- style?: React.CSSProperties;
22
- overlayClassName?: string;
23
- overlayZIndex?: string;
24
- overlayStyle?: React.CSSProperties;
25
- portalContainer?: HTMLElement | null;
26
- }
27
-
28
- export const Sheet: React.FC<SheetProps> = ({
29
- children,
30
- side = "right",
31
- title,
32
- modal = true,
33
- includeBackgroundOverlay = true,
34
- open,
35
- onOpenChange,
36
- onPointerDownOutside,
37
- onInteractOutside,
38
- transparent,
39
- className,
40
- style,
41
- overlayClassName,
42
- overlayZIndex = "z-50",
43
- overlayStyle,
44
- portalContainer,
45
- ...props
46
- }) => {
47
- const [displayed, setDisplayed] = useState(false);
48
- const [contentEl, setContentEl] = useState<HTMLDivElement | null>(null);
49
-
50
- // Get the portal container from context
51
- const contextContainer = usePortalContainer();
52
-
53
- // Prioritize manual prop, fallback to context container
54
- const finalContainer = (portalContainer ?? contextContainer ?? undefined) as HTMLElement | undefined;
55
-
56
- useEffect(() => {
57
- const raf = requestAnimationFrame(() => {
58
- setDisplayed(open);
59
- });
60
- return () => cancelAnimationFrame(raf);
61
- }, [open]);
62
-
63
- const transformValue: Record<string, string> = {
64
- top: "-translate-y-full",
65
- bottom: "translate-y-full",
66
- left: "-translate-x-full",
67
- right: "translate-x-full"
68
- };
69
-
70
- const borderClass: Record<string, string> = {
71
- top: "border-b",
72
- bottom: "border-t",
73
- left: "border-r",
74
- right: "border-l"
75
- };
76
-
77
- return (
78
- <DialogPrimitive.Root open={displayed || open}
79
- modal={modal}
80
- onOpenChange={onOpenChange}>
81
- <DialogPrimitive.Portal container={finalContainer}>
82
- {includeBackgroundOverlay && <DialogPrimitive.Overlay
83
- className={cls(
84
- "outline-none",
85
- "fixed inset-0 bg-white/80 dark:bg-surface-900/80",
86
- "backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
87
- overlayZIndex,
88
- overlayClassName
89
- )}
90
- style={overlayStyle}
91
- />}
92
- <DialogPrimitive.Content
93
- {...props}
94
- ref={setContentEl}
95
- onOpenAutoFocus={(event) => event.preventDefault()}
96
- onPointerDownOutside={onPointerDownOutside}
97
- onInteractOutside={onInteractOutside}
98
- className={cls(
99
- "outline-none",
100
- borderClass[side],
101
- defaultBorderMixin,
102
- // No `will-change: transform` / `transform-gpu` here, however
103
- // tempting the layer hint is on a panel this size. Either one
104
- // makes this element a *containing block* for its
105
- // `position: fixed` descendants, and everything portaled into
106
- // the panel below — a Select dropdown, above all — is fixed and
107
- // positioned in viewport coordinates. Inside a containing block
108
- // those coordinates are resolved against the panel instead, so
109
- // every popup was displaced by the panel's own offset and a
110
- // right-hand Select opened its list off the edge of the screen:
111
- // the dropdown was open, just nowhere anyone could see it.
112
- "text-surface-accent-900 dark:text-white",
113
- "fixed transform z-50 transition-[transform,opacity] ease-in-out",
114
- !displayed ? "duration-150" : "duration-100",
115
- "outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus:ring-0",
116
- transparent ? "" : "shadow-md bg-white dark:bg-surface-900",
117
- side === "top" || side === "bottom" ? "w-full" : "h-full",
118
- side === "left" || side === "top" ? "left-0 top-0" : "right-0 bottom-0",
119
- displayed && open ? "opacity-100" : "opacity-50",
120
- !displayed || !open ? transformValue[side] : "",
121
- className
122
- )}
123
- style={style}
124
- >
125
- <DialogPrimitive.Title className="sr-only outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0 focus:ring-0">
126
- {title ?? "Sheet"}
127
- </DialogPrimitive.Title>
128
- <PortalContainerProvider container={contentEl}>
129
- {children}
130
- </PortalContainerProvider>
131
- </DialogPrimitive.Content>
132
- </DialogPrimitive.Portal>
133
- </DialogPrimitive.Root>
134
- );
135
- };
@@ -1,54 +0,0 @@
1
- import React from "react";
2
- import { cls } from "../util";
3
- import { useInjectStyles } from "../hooks";
4
-
5
- export type SkeletonProps = {
6
- width?: number;
7
- height?: number;
8
- className?: string;
9
- }
10
-
11
- const styles = `
12
- @keyframes shimmer {
13
- 0% {
14
- transform: translateX(-150%);
15
- }
16
- 100% {
17
- transform: translateX(150%);
18
- }
19
- }
20
- `;
21
-
22
- export function Skeleton({
23
- width,
24
- height,
25
- className
26
- }: SkeletonProps) {
27
-
28
- useInjectStyles("Skeleton", styles);
29
-
30
- return <span
31
- style={{
32
- width: width === undefined ? undefined : `${width}px`,
33
- height: height === undefined ? undefined : `${height}px`
34
- }}
35
- className={
36
- cls(
37
- "block relative overflow-hidden",
38
- "bg-surface-accent-50 dark:bg-surface-accent-800 rounded-md",
39
- "max-w-full max-h-full",
40
- // The defaults are classes, not inline styles, so that a caller can
41
- // override them: an inline style beats every utility, which is why
42
- // `<Skeleton className="w-full h-full"/>` inside a 40px thumbnail
43
- // box used to render a 12px bar. The `width`/`height` props still
44
- // win over any class, since those do land inline.
45
- width === undefined ? "w-full" : undefined,
46
- height === undefined ? "h-3" : undefined,
47
- className)
48
- }>
49
- <span
50
- className="absolute inset-0 bg-gradient-to-r from-transparent via-white/50 dark:via-white/8 to-transparent"
51
- style={{ animation: "shimmer 1.8s ease-in-out infinite" }}
52
- />
53
- </span>;
54
- }
@@ -1,110 +0,0 @@
1
- "use client";
2
- import * as React from "react";
3
- import { cls } from "../util";
4
- import * as SliderPrimitive from "@radix-ui/react-slider";
5
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
6
-
7
- export interface SliderProps {
8
- className?: string;
9
- name?: string;
10
- disabled?: boolean;
11
- orientation?: React.AriaAttributes["aria-orientation"];
12
- dir?: "ltr" | "rtl";
13
- min?: number;
14
- max?: number;
15
- step?: number;
16
- minStepsBetweenThumbs?: number;
17
- value?: number[];
18
- defaultValue?: number[];
19
- onValueChange?: (value: number[]) => void;
20
- onValueCommit?: (value: number[]) => void;
21
- inverted?: boolean;
22
- form?: string;
23
- size?: "small" | "regular";
24
- }
25
-
26
- function SliderThumb(props: {
27
- props: Omit<React.PropsWithoutRef<SliderProps>, "size" | "className">,
28
- index: number,
29
- hovered: boolean,
30
- classes: string
31
- }) {
32
- return <TooltipPrimitive.Root open={props.hovered}>
33
- <TooltipPrimitive.Trigger asChild>
34
- <SliderPrimitive.Thumb
35
- className={cls({
36
- "border-primary bg-primary outline-none": !props.props.disabled,
37
- "border-surface-accent-300 bg-surface-accent-300 dark:border-surface-700 dark:bg-surface-700": props.props.disabled
38
- },
39
- props.classes,
40
- "focus-visible:ring-4 focus-visible:ring-primary focus-visible:ring-opacity-50 focus-visible:ring-primary/50",
41
- "hover:ring-4 hover:ring-primary hover:ring-opacity-25 hover:ring-primary/25",
42
- "block rounded-full transition-colors focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50")}
43
-
44
- />
45
- </TooltipPrimitive.Trigger>
46
- <TooltipPrimitive.Content side="top"
47
- sideOffset={5}
48
- className={cls(
49
- "TooltipContent",
50
- "max-w-lg leading-relaxed",
51
- "z-50 rounded-md px-3 py-2 text-xs leading-none bg-surface-accent-700 dark:bg-surface-accent-800 bg-opacity-90 bg-surface-accent-700/90 dark:bg-surface-accent-800/90 font-medium text-surface-accent-50 shadow-2xl select-none duration-400 ease-in transform opacity-100"
52
- )}>
53
- {props.props.value?.[props.index]}
54
- </TooltipPrimitive.Content>
55
- </TooltipPrimitive.Root>;
56
- }
57
-
58
- const Slider = React.forwardRef<
59
- React.ElementRef<typeof SliderPrimitive.Root>,
60
- SliderProps
61
- >(({
62
- className,
63
- size = "regular",
64
- ...props
65
- }, ref) => {
66
- const [hovered, setHovered] = React.useState(false);
67
-
68
- const thumbSizeClasses =
69
- size === "small"
70
- ? "h-4 w-4" // Smaller size for the thumb
71
- : "h-6 w-6"; // Default size
72
-
73
- return (
74
- <TooltipPrimitive.Provider delayDuration={200}>
75
- <SliderPrimitive.Root
76
- ref={ref}
77
- onMouseEnter={() => setHovered(true)}
78
- onMouseLeave={() => setHovered(false)}
79
- className={cls(
80
- "relative flex w-full touch-none select-none items-center",
81
- className
82
- )}
83
- {...props}
84
- >
85
- <SliderPrimitive.Track
86
- style={{ height: size === "small" ? 4 : 8 }}
87
- className={"relative w-full grow overflow-hidden rounded-full bg-surface-accent-300 bg-opacity-40 bg-surface-accent-300/40 dark:bg-surface-700 dark:bg-opacity-40 dark:bg-surface-700/40"}>
88
-
89
- <SliderPrimitive.Range
90
- className={cls("absolute h-full", {
91
- "bg-primary": !props.disabled,
92
- "bg-surface-accent-300 dark:bg-surface-700": props.disabled
93
- })}
94
- />
95
- </SliderPrimitive.Track>
96
-
97
- {(props.value ?? [0]).map((_, index) => <SliderThumb
98
- key={index}
99
- index={index}
100
- props={props}
101
- hovered={hovered}
102
- classes={thumbSizeClasses}/>)}
103
- </SliderPrimitive.Root>
104
- </TooltipPrimitive.Provider>
105
- );
106
- });
107
-
108
- Slider.displayName = "Slider";
109
-
110
- export { Slider };
@@ -1,178 +0,0 @@
1
-
2
- "use client";
3
-
4
- import { TagIcon } from "lucide-react";
5
- import React, { useRef } from "react";
6
- import { defaultBorderMixin } from "../styles";
7
- import { cls } from "../util";
8
-
9
- export type TableProps = {
10
- children: React.ReactNode;
11
- className?: string;
12
- style?: React.CSSProperties;
13
- } & React.TableHTMLAttributes<HTMLTableElement>;
14
-
15
- export const Table = React.memo(({
16
- children,
17
- className,
18
- style,
19
- ...rest
20
- }: TableProps) => (
21
- <table
22
- className={cls("text-left text-text-primary dark:text-text-primary-dark rounded-lg overflow-x-auto", className)}
23
- style={style}
24
- {...rest}
25
- >
26
- {children}
27
- </table>
28
- ));
29
-
30
- export type TableBodyProps = {
31
- children?: React.ReactNode;
32
- className?: string;
33
- } & React.HTMLAttributes<HTMLTableSectionElement>;
34
-
35
- export const TableBody = React.memo(({
36
- children,
37
- className,
38
- ...rest
39
- }: TableBodyProps) => (
40
- <tbody
41
- className={cls("bg-white dark:bg-surface-900 text-sm divide-y divide-surface-100 dark:divide-surface-700 dark:divide-opacity-70 dark:divide-surface-700/70", className)}
42
- {...rest}
43
- >
44
- {children}
45
- </tbody>
46
- ));
47
-
48
- export type TableHeaderProps = {
49
- children?: React.ReactNode;
50
- className?: string;
51
- } & React.HTMLAttributes<HTMLTableSectionElement>;
52
-
53
- export const TableHeader = React.memo(({
54
- children,
55
- className,
56
- ...rest
57
- }: TableHeaderProps) => (
58
- <thead {...rest}>
59
- <tr
60
- className={cls(
61
- defaultBorderMixin,
62
- "text-sm font-medium text-surface-700 dark:text-surface-accent-300",
63
- "bg-surface-accent-50 border-b dark:bg-surface-800",
64
- className
65
- )}
66
- >
67
- {children}
68
- </tr>
69
- </thead>
70
- ));
71
-
72
- export type TableRowProps = {
73
- children?: React.ReactNode;
74
- className?: string;
75
- onClick?: React.MouseEventHandler<any>;
76
- style?: React.CSSProperties;
77
- } & React.HTMLAttributes<HTMLTableRowElement>;
78
-
79
- export const TableRow = React.memo(({
80
- children,
81
- className,
82
- onClick,
83
- style,
84
- ...rest
85
- }: TableRowProps) => (
86
- <tr
87
- onClick={onClick}
88
- style={style}
89
- className={cls(
90
- "bg-white dark:bg-surface-900",
91
- onClick ? "transition-colors duration-150 hover:bg-primary/5 cursor-pointer" : "",
92
- className
93
- )}
94
- {...rest}
95
- >
96
- {children}
97
- </tr>
98
- ));
99
-
100
- export type TableCellProps = {
101
- children?: React.ReactNode;
102
- header?: boolean;
103
- scope?: string;
104
- className?: string;
105
- style?: React.CSSProperties;
106
- align?: "left" | "center" | "right";
107
- colspan?: number;
108
- } & React.HTMLAttributes<HTMLTableCellElement>;
109
-
110
- export const TableCell = React.memo(({
111
- children,
112
- header = false,
113
- scope = "",
114
- align,
115
- className,
116
- style,
117
- colspan,
118
- ...rest
119
- }: TableCellProps) => {
120
- const ref = useRef<HTMLTableCellElement>(null);
121
- const TagIcon = header || getParentName(ref.current) === "TableHeader" ? "th" : "td";
122
- return (
123
- <TagIcon
124
- scope={scope}
125
- colSpan={colspan}
126
- ref={ref}
127
- style={style}
128
- className={cls(
129
- "px-4 py-3 text-clip ",
130
- align === "center" ? "text-center" : (align === "right" ? "text-right" : "text-left"),
131
- className
132
- )}
133
- {...rest}
134
- >
135
- {children}
136
- </TagIcon>
137
- );
138
- });
139
-
140
- interface ReactFiber {
141
- return: ReactFiber;
142
- type: string | Function;
143
- elementType?: {
144
- name?: string;
145
- };
146
- }
147
-
148
- // This is highly experimental and might break in the future
149
- function getParentName(element: HTMLElement | null): string | undefined {
150
- if (element) {
151
- const key = Object.keys(element).find((key) => {
152
- return (
153
- key.startsWith("__reactFiber$") ||
154
- key.startsWith("__reactInternalInstance$")
155
- );
156
- });
157
- if (key) {
158
- const domFiber = (element as unknown as Record<string, ReactFiber>)[key];
159
- const getComponentFiber = (fiber: ReactFiber): ReactFiber => {
160
- let parentFiber = fiber.return;
161
- while (parentFiber && typeof parentFiber.type === "string") {
162
- parentFiber = parentFiber.return;
163
- }
164
- return parentFiber;
165
- };
166
- let fiber = getComponentFiber(domFiber);
167
- fiber = getComponentFiber(fiber);
168
- return fiber?.elementType?.name;
169
- }
170
- }
171
- return undefined;
172
- }
173
-
174
- Table.displayName = "Table";
175
- TableBody.displayName = "TableBody";
176
- TableHeader.displayName = "TableHeader";
177
- TableRow.displayName = "TableRow";
178
- TableCell.displayName = "TableCell";
@@ -1,185 +0,0 @@
1
-
2
- import React, { createContext, useContext, useRef, useState, useEffect, useMemo } from "react";
3
- import * as TabsPrimitive from "@radix-ui/react-tabs";
4
- import { cls } from "../util";
5
- import { defaultBorderMixin } from "../styles";
6
-
7
- export type TabVariant = "standard" | "boxy" | "pill";
8
-
9
- const TabsContext = createContext<{ variant: TabVariant }>({ variant: "standard" });
10
- import { IconButton } from "./IconButton";
11
- import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
12
- import { iconSize } from "../icons/Icon";
13
-
14
- export type TabsProps = {
15
- value: string,
16
- children: React.ReactNode,
17
- innerClassName?: string,
18
- className?: string,
19
- variant?: TabVariant,
20
- onValueChange: (value: string) => void
21
- };
22
-
23
- export function Tabs({
24
- value,
25
- onValueChange,
26
- className,
27
- innerClassName,
28
- variant = "standard",
29
- children
30
- }: TabsProps) {
31
- const scrollContainerRef = useRef<HTMLDivElement>(null);
32
- const [showLeftScroll, setShowLeftScroll] = useState(false);
33
- const [showRightScroll, setShowRightScroll] = useState(false);
34
- const [isScrollable, setIsScrollable] = useState(false);
35
-
36
- const checkScroll = () => {
37
- if (scrollContainerRef.current) {
38
- const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
39
- setShowLeftScroll(scrollLeft > 0);
40
- setShowRightScroll(Math.ceil(scrollLeft + clientWidth) < scrollWidth);
41
- setIsScrollable(scrollWidth > clientWidth);
42
- }
43
- };
44
-
45
- useEffect(() => {
46
- checkScroll();
47
- window.addEventListener("resize", checkScroll);
48
-
49
- let observer: ResizeObserver;
50
- if (scrollContainerRef.current) {
51
- observer = new ResizeObserver(checkScroll);
52
- observer.observe(scrollContainerRef.current);
53
- if (scrollContainerRef.current.firstElementChild) {
54
- observer.observe(scrollContainerRef.current.firstElementChild);
55
- }
56
- }
57
-
58
- return () => {
59
- window.removeEventListener("resize", checkScroll);
60
- observer?.disconnect();
61
- };
62
- }, [children]);
63
-
64
- const scroll = (direction: "left" | "right") => {
65
- if (scrollContainerRef.current) {
66
- const container = scrollContainerRef.current;
67
- const scrollAmount = Math.max(container.clientWidth / 2, 200);
68
- const targetScroll = container.scrollLeft + (direction === "left" ? -scrollAmount : scrollAmount);
69
-
70
- container.scrollTo({
71
- left: targetScroll,
72
- behavior: "smooth"
73
- });
74
- // checkScroll will be called by onScroll event
75
- }
76
- };
77
-
78
- const contextValue = useMemo(() => ({ variant }), [variant]);
79
-
80
- return <TabsContext.Provider value={contextValue}>
81
- <TabsPrimitive.Root
82
- value={value}
83
- onValueChange={onValueChange}
84
- className={cls("relative flex flex-row items-center min-w-0 w-full", className)}
85
- >
86
- {isScrollable && (
87
- <button
88
- type="button"
89
- disabled={!showLeftScroll}
90
- aria-label="Scroll tabs left"
91
- onClick={() => scroll("left")}
92
- className={cls(
93
- "absolute left-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md transition-all h-8 w-6",
94
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400",
95
- !showLeftScroll ? "pointer-events-none opacity-0" : "text-surface-600 dark:text-surface-400 hover:bg-surface-accent-200 dark:hover:bg-surface-accent-800",
96
- "bg-surface-50 dark:bg-surface-900 border shadow-sm", defaultBorderMixin
97
- )}
98
- >
99
- <ChevronLeftIcon size={iconSize.smallest}/>
100
- </button>
101
- )}
102
- <div
103
- ref={scrollContainerRef}
104
- className="flex-1 overflow-x-auto no-scrollbar min-w-0"
105
- onScroll={checkScroll}
106
- style={{ scrollbarWidth: "none",
107
- msOverflowStyle: "none" }}
108
- >
109
- <TabsPrimitive.List className={cls(
110
- variant === "standard" && "inline-flex h-9 items-center justify-start rounded-md bg-surface-50 p-1 text-surface-600 dark:bg-surface-900 dark:text-surface-400 gap-2 border",
111
- variant === "standard" && defaultBorderMixin,
112
- variant === "boxy" && "flex items-center h-full",
113
- variant === "pill" && "flex items-center gap-0.5",
114
- innerClassName)
115
- }>
116
- {children}
117
- </TabsPrimitive.List>
118
- </div>
119
- {isScrollable && (
120
- <button
121
- type="button"
122
- disabled={!showRightScroll}
123
- aria-label="Scroll tabs right"
124
- onClick={() => scroll("right")}
125
- className={cls(
126
- "absolute right-0 top-1/2 -translate-y-1/2 z-10 flex items-center justify-center rounded-md transition-all h-8 w-6",
127
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400",
128
- !showRightScroll ? "pointer-events-none opacity-0" : "text-surface-600 dark:text-surface-400 hover:bg-surface-accent-200 dark:hover:bg-surface-accent-800",
129
- "bg-surface-50 dark:bg-surface-900 border shadow-sm", defaultBorderMixin
130
- )}
131
- >
132
- <ChevronRightIcon size={iconSize.smallest}/>
133
- </button>
134
- )}
135
- </TabsPrimitive.Root>
136
- </TabsContext.Provider>;
137
- }
138
-
139
- export type TabProps = {
140
- value: string,
141
- className?: string,
142
- innerClassName?: string,
143
- children: React.ReactNode,
144
- disabled?: boolean
145
- };
146
-
147
- export function Tab({
148
- value,
149
- className,
150
- innerClassName,
151
- children,
152
- disabled
153
- }: TabProps) {
154
- const { variant } = useContext(TabsContext);
155
-
156
- return (
157
- <TabsPrimitive.Trigger
158
- value={value}
159
- disabled={disabled}
160
- className={cls(
161
- "inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-white transition-all",
162
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-surface-400 focus-visible:ring-offset-2",
163
- "disabled:pointer-events-none disabled:opacity-50",
164
- variant === "standard" && "rounded-md px-3 py-1 data-[state=active]:bg-white data-[state=active]:text-surface-900 data-[state=active]:shadow-sm dark:data-[state=active]:bg-surface-900 dark:data-[state=active]:text-surface-50",
165
- variant === "boxy" && cls(
166
- "flex-shrink-0 flex items-center gap-1.5 px-3.5 h-9 border-r border-surface-200 dark:border-surface-800 cursor-pointer text-xs font-medium transition-colors group relative box-border overflow-hidden",
167
- "border-b-2 border-b-transparent",
168
- "data-[state=active]:bg-surface-50 dark:data-[state=active]:bg-surface-900",
169
- "data-[state=active]:text-text-primary dark:data-[state=active]:text-text-primary-dark",
170
- "data-[state=active]:border-b-primary",
171
- "text-text-secondary dark:text-text-secondary-dark hover:bg-surface-100 dark:hover:bg-surface-800"
172
- ),
173
- variant === "pill" && cls(
174
- "px-2 py-0.5 rounded-md text-[10px] font-medium transition-colors",
175
- "data-[state=active]:bg-primary/10 data-[state=active]:text-primary dark:data-[state=active]:bg-primary/20 dark:data-[state=active]:text-primary",
176
- "text-text-disabled dark:text-text-disabled-dark hover:text-text-secondary dark:hover:text-text-secondary-dark"
177
- ),
178
- className,
179
- variant === "standard" && innerClassName
180
- )}
181
- >
182
- {children}
183
- </TabsPrimitive.Trigger>
184
- );
185
- }