@noya-app/noya-designsystem 0.1.64 → 0.1.65

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 (115) hide show
  1. package/.turbo/turbo-build.log +13 -10
  2. package/CHANGELOG.md +12 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.d.mts +501 -228
  5. package/dist/index.d.ts +501 -228
  6. package/dist/index.js +6738 -2571
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +6697 -2499
  9. package/dist/index.mjs.map +1 -1
  10. package/package.json +6 -6
  11. package/src/components/ActivityIndicator.tsx +9 -4
  12. package/src/components/ActivityLog.tsx +197 -0
  13. package/src/components/AnimatePresence.tsx +37 -22
  14. package/src/components/Avatar.tsx +42 -25
  15. package/src/components/Banner.tsx +57 -11
  16. package/src/components/BaseToolbar.tsx +29 -7
  17. package/src/components/Breadcrumbs.tsx +2 -2
  18. package/src/components/Button.tsx +23 -24
  19. package/src/components/Checkbox.tsx +6 -35
  20. package/src/components/Chip.tsx +45 -33
  21. package/src/components/Collection.tsx +16 -11
  22. package/src/components/ColorSwatch.tsx +3 -3
  23. package/src/components/ColorSwatchControl.tsx +2 -2
  24. package/src/components/Combobox.tsx +6 -6
  25. package/src/components/ComboboxMenu.tsx +6 -5
  26. package/src/components/CommandPalette.tsx +1 -1
  27. package/src/components/Dialog.tsx +6 -12
  28. package/src/components/Divider.tsx +8 -8
  29. package/src/components/DraggableMenuButton.tsx +9 -5
  30. package/src/components/Drawer.tsx +5 -5
  31. package/src/components/DropdownMenu.tsx +1 -1
  32. package/src/components/EditableText.tsx +2 -2
  33. package/src/components/Fade.tsx +13 -13
  34. package/src/components/FileUploadIndicator.tsx +11 -11
  35. package/src/components/FloatingWindow.tsx +2 -2
  36. package/src/components/Grid.tsx +18 -11
  37. package/src/components/GridView.tsx +32 -25
  38. package/src/components/IVirtualizedList.tsx +5 -0
  39. package/src/components/Icons.tsx +24 -4
  40. package/src/components/InputField.tsx +19 -19
  41. package/src/components/InspectorContainer.tsx +2 -2
  42. package/src/components/InspectorPrimitives.tsx +15 -9
  43. package/src/components/Label.tsx +4 -3
  44. package/src/components/LabeledElementView.tsx +3 -3
  45. package/src/components/LabeledField.tsx +6 -6
  46. package/src/components/List.tsx +103 -45
  47. package/src/components/ListMenu.tsx +91 -0
  48. package/src/components/ListNavigator.tsx +106 -0
  49. package/src/components/ListView.tsx +20 -1158
  50. package/src/components/MediaThumbnail.tsx +56 -15
  51. package/src/components/Message.tsx +5 -5
  52. package/src/components/Navigator.tsx +461 -0
  53. package/src/components/NoyaLogo.tsx +1 -1
  54. package/src/components/Popover.tsx +9 -5
  55. package/src/components/Progress.tsx +19 -9
  56. package/src/components/ResizableContainer.tsx +187 -0
  57. package/src/components/RingProgress.tsx +128 -0
  58. package/src/components/ScrollArea.tsx +4 -4
  59. package/src/components/ScrollableSidebar.tsx +10 -0
  60. package/src/components/SearchCompletionMenu.tsx +3 -3
  61. package/src/components/Section.tsx +107 -57
  62. package/src/components/SegmentedControl.tsx +29 -29
  63. package/src/components/SelectMenu.tsx +13 -20
  64. package/src/components/SelectionToolbar.tsx +4 -3
  65. package/src/components/Slider.tsx +9 -9
  66. package/src/components/Spacer.tsx +2 -2
  67. package/src/components/StackNavigator.tsx +378 -0
  68. package/src/components/Stepper.tsx +88 -0
  69. package/src/components/Switch.tsx +4 -4
  70. package/src/components/Tabs.tsx +3 -3
  71. package/src/components/Text.tsx +23 -13
  72. package/src/components/TextArea.tsx +3 -3
  73. package/src/components/Toast.tsx +4 -4
  74. package/src/components/Toolbar.tsx +50 -9
  75. package/src/components/ToolbarDrawer.tsx +2 -2
  76. package/src/components/Tooltip.tsx +1 -1
  77. package/src/components/TreeView.tsx +11 -4
  78. package/src/components/UserPointer.tsx +4 -4
  79. package/src/components/ai-assistant/AIAssistantLayout.tsx +8 -8
  80. package/src/components/blocks/ImageBlockComponent.tsx +13 -7
  81. package/src/components/connected-users-menu/ConnectedUsersMenuLayout.tsx +4 -4
  82. package/src/components/file-explorer/FileExplorerLayout.tsx +20 -8
  83. package/src/components/internal/Checkmark.tsx +1 -1
  84. package/src/components/internal/Menu.tsx +22 -18
  85. package/src/components/internal/MenuViewport.tsx +13 -6
  86. package/src/components/internal/SelectItem.tsx +3 -3
  87. package/src/components/internal/TextInput.tsx +5 -1
  88. package/src/components/listView/ListViewContexts.tsx +68 -0
  89. package/src/components/listView/ListViewEditableRowTitle.tsx +55 -0
  90. package/src/components/listView/ListViewRoot.tsx +521 -0
  91. package/src/components/listView/ListViewRow.tsx +475 -0
  92. package/src/components/listView/ListViewRowTitle.tsx +21 -0
  93. package/src/components/listView/types.ts +11 -0
  94. package/src/components/pipeline/PipelineResultLayout.tsx +6 -6
  95. package/src/components/sorting/DragRegistration.tsx +2 -1
  96. package/src/components/sorting/SharedDragProvider.tsx +91 -9
  97. package/src/components/sorting/Sortable.tsx +71 -17
  98. package/src/components/workspace/DrawerWorkspaceLayout.tsx +5 -5
  99. package/src/components/workspace/PanelWorkspaceLayout.tsx +65 -49
  100. package/src/components/workspace/VerticalTabMenu.tsx +25 -15
  101. package/src/components/workspace/WorkspaceLayout.tsx +30 -21
  102. package/src/contexts/DialogContext.tsx +17 -5
  103. package/src/hooks/useIndent.ts +3 -8
  104. package/src/index.css +24 -10
  105. package/src/index.tsx +10 -5
  106. package/src/utils/classNames.ts +52 -6
  107. package/src/utils/editableBlockStyles.ts +2 -2
  108. package/src/utils/formatByteSize.ts +1 -0
  109. package/src/utils/inputs.ts +8 -6
  110. package/src/utils/sketchColor.ts +0 -34
  111. package/tailwind.config.ts +1 -0
  112. package/src/components/FillInputField.tsx +0 -37
  113. package/src/components/FillPreviewBackground.tsx +0 -134
  114. package/src/components/GradientPicker.tsx +0 -90
  115. package/src/utils/getGradientBackground.tsx +0 -31
@@ -10,11 +10,15 @@ type ColorScheme = "normal" | "warning" | "primary" | "secondary";
10
10
  export function Progress({
11
11
  value,
12
12
  colorScheme = "normal",
13
+ color,
13
14
  className,
14
- style,
15
+ style: styleProp,
15
16
  }: {
17
+ /** A value between 0 and 100. */
16
18
  value: number;
19
+
17
20
  colorScheme?: ColorScheme;
21
+ color?: string;
18
22
  className?: string;
19
23
  style?: React.CSSProperties;
20
24
  }) {
@@ -22,26 +26,32 @@ export function Progress({
22
26
  const transformStyles = React.useMemo(
23
27
  () => ({
24
28
  transform: `translateX(-${100 - clampedValue}%)`,
29
+ backgroundColor: color,
25
30
  }),
26
- [clampedValue]
31
+ [color, clampedValue]
32
+ );
33
+
34
+ const style = React.useMemo(
35
+ () => ({ transform: "translateZ(0)", ...styleProp }),
36
+ [styleProp]
27
37
  );
28
38
 
29
39
  return (
30
40
  <ProgressPrimitive.Root
31
41
  className={cx(
32
- `relative overflow-hidden bg-input-background h-[5px]`,
42
+ `n-relative n-overflow-hidden n-bg-input-background n-h-[5px]`,
33
43
  className
34
44
  )}
35
- style={{ transform: "translateZ(0)", ...style }}
45
+ style={style}
36
46
  value={clampedValue}
37
47
  >
38
48
  <ProgressPrimitive.Indicator
39
49
  className={cx(
40
- "transition-[transform_660ms_cubic-bezier(0.65,0,0.35,1) w-full h-full",
41
- colorScheme === "primary" && "bg-primary",
42
- colorScheme === "secondary" && "bg-secondary",
43
- colorScheme === "warning" && "bg-warning",
44
- colorScheme === "normal" && "bg-text"
50
+ "n-transition-[transform_660ms_cubic-bezier(0.65,0,0.35,1)] n-w-full n-h-full",
51
+ colorScheme === "primary" && "n-bg-primary",
52
+ colorScheme === "secondary" && "n-bg-secondary",
53
+ colorScheme === "warning" && "n-bg-warning",
54
+ colorScheme === "normal" && "n-bg-text"
45
55
  )}
46
56
  style={transformStyles}
47
57
  />
@@ -0,0 +1,187 @@
1
+ "use client";
2
+ import { createClickCounter } from "@noya-app/react-utils";
3
+ import React, { ReactNode, useCallback, useRef, useState } from "react";
4
+
5
+ interface ResizableContainerProps {
6
+ children: ReactNode | ((children: { width?: number }) => ReactNode);
7
+ minWidth: number;
8
+ maxWidth?: number;
9
+ style?: React.CSSProperties;
10
+ innerStyle?: React.CSSProperties;
11
+ handleContainerStyle?: React.CSSProperties;
12
+ handleStyle?: React.CSSProperties;
13
+ className?: string;
14
+ onChangeWidth?: (width: number) => void;
15
+ shouldResetWidthOnGestureEnd?: boolean;
16
+ }
17
+
18
+ export const ResizableContainer: React.FC<ResizableContainerProps> = ({
19
+ children,
20
+ minWidth,
21
+ maxWidth,
22
+ style,
23
+ innerStyle,
24
+ handleContainerStyle,
25
+ handleStyle,
26
+ className,
27
+ onChangeWidth,
28
+ shouldResetWidthOnGestureEnd: shouldResetWidth,
29
+ }) => {
30
+ const containerRef = useRef<HTMLDivElement | null>(null);
31
+ const resizeableRef = useRef<HTMLDivElement | null>(null);
32
+ const handleRef = useRef<HTMLDivElement | null>(null);
33
+ const clickCounter = useRef(createClickCounter({ delay: 250 }));
34
+
35
+ const [width, setWidth] = useState<number>();
36
+ const [drag, setDrag] = useState<{
37
+ startX: number;
38
+ initialWidth: number;
39
+ minWidth: number;
40
+ maxWidth: number;
41
+ }>();
42
+
43
+ const handlePointerDown = useCallback(
44
+ (event: React.PointerEvent<HTMLDivElement>) => {
45
+ const containerWidth =
46
+ containerRef.current?.getBoundingClientRect().width;
47
+ const resizeableWidth =
48
+ resizeableRef.current?.getBoundingClientRect().width;
49
+
50
+ if (containerWidth === undefined) return;
51
+ if (resizeableWidth === undefined) return;
52
+
53
+ // start pointer capture
54
+ handleRef.current?.setPointerCapture(event.pointerId);
55
+
56
+ setDrag({
57
+ startX: event.clientX,
58
+ initialWidth: resizeableWidth,
59
+ minWidth: minWidth,
60
+ maxWidth: maxWidth ?? containerWidth,
61
+ });
62
+
63
+ event.preventDefault();
64
+ event.stopPropagation();
65
+ },
66
+ [maxWidth, minWidth]
67
+ );
68
+
69
+ const handlePointerMove = useCallback(
70
+ (event: React.PointerEvent<HTMLDivElement>) => {
71
+ if (!drag) return;
72
+
73
+ const delta = event.clientX - drag.startX;
74
+
75
+ let newWidth = clamp(
76
+ drag.initialWidth + delta,
77
+ drag.minWidth,
78
+ drag.maxWidth
79
+ );
80
+
81
+ setWidth(newWidth);
82
+ onChangeWidth?.(newWidth);
83
+
84
+ event.preventDefault();
85
+ event.stopPropagation();
86
+ },
87
+ [drag, onChangeWidth]
88
+ );
89
+
90
+ const handlePointerUp = useCallback(
91
+ (event: React.PointerEvent<HTMLDivElement>) => {
92
+ setDrag(undefined);
93
+
94
+ // Release pointer
95
+ handleRef.current?.releasePointerCapture(event.pointerId);
96
+
97
+ event.preventDefault();
98
+ event.stopPropagation();
99
+
100
+ const clickCount = clickCounter.current.handleClick({
101
+ x: event.clientX,
102
+ y: event.clientY,
103
+ });
104
+
105
+ if (clickCount >= 2 || shouldResetWidth) {
106
+ setWidth(undefined);
107
+ }
108
+ },
109
+ [shouldResetWidth]
110
+ );
111
+
112
+ return (
113
+ <div
114
+ ref={containerRef}
115
+ id={"resize"}
116
+ style={{ position: "relative", ...style }}
117
+ className={className}
118
+ >
119
+ <div
120
+ ref={resizeableRef}
121
+ style={{
122
+ position: "relative",
123
+ width: width !== undefined ? `${width}px` : "auto",
124
+ ...innerStyle,
125
+ }}
126
+ >
127
+ {typeof children === "function" ? children({ width }) : children}
128
+ <div
129
+ ref={handleRef}
130
+ style={{
131
+ position: "absolute",
132
+ right: "-1.25rem",
133
+ bottom: 0,
134
+ top: 0,
135
+ display: "flex",
136
+ width: "1rem",
137
+ cursor: "ew-resize",
138
+ touchAction: "none",
139
+ flexDirection: "column",
140
+ justifyContent: "center",
141
+ paddingLeft: "5px",
142
+ paddingRight: "5px",
143
+ opacity: 1,
144
+ ...handleContainerStyle,
145
+ }}
146
+ onPointerDown={handlePointerDown}
147
+ onPointerMove={handlePointerMove}
148
+ onPointerUp={handlePointerUp}
149
+ onPointerCancel={handlePointerUp}
150
+ >
151
+ <div
152
+ style={{
153
+ position: "relative",
154
+ display: "flex",
155
+ height: "2.5rem",
156
+ width: "100%",
157
+ flexDirection: "column",
158
+ alignItems: "center",
159
+ justifyContent: "center",
160
+ borderRadius: "9999px",
161
+ backgroundColor: "rgba(17, 24, 39, 0.5)",
162
+ ...handleStyle,
163
+ }}
164
+ ></div>
165
+ </div>
166
+ {/* Prevent iframe from capturing pointer events */}
167
+ {drag && (
168
+ <div
169
+ style={{
170
+ position: "fixed",
171
+ inset: 0,
172
+ zIndex: 50,
173
+ cursor: "ew-resize",
174
+ }}
175
+ onPointerMove={handlePointerMove}
176
+ onPointerUp={handlePointerUp}
177
+ onPointerCancel={handlePointerUp}
178
+ />
179
+ )}
180
+ </div>
181
+ </div>
182
+ );
183
+ };
184
+
185
+ function clamp(value: number, min: number, max: number) {
186
+ return Math.min(Math.max(value, min), max);
187
+ }
@@ -0,0 +1,128 @@
1
+ "use client";
2
+
3
+ import { clamp } from "@noya-app/noya-utils";
4
+ import * as React from "react";
5
+ import { cx } from "../utils/classNames";
6
+
7
+ type ColorScheme = "normal" | "warning" | "primary" | "secondary";
8
+
9
+ export function RingProgress({
10
+ value,
11
+ dividedBy = 100,
12
+ size = 24,
13
+ thickness = 3,
14
+ colorScheme = "normal",
15
+ color,
16
+ trackColor,
17
+ className,
18
+ style,
19
+ ariaLabel,
20
+ }: {
21
+ /** Current value (numerator). */
22
+ value: number;
23
+ /** Total value representing 100%. Defaults to 100. */
24
+ dividedBy?: number;
25
+ /** Diameter in pixels of the ring (outer size). */
26
+ size?: number;
27
+ /** Stroke width of the ring in pixels. */
28
+ thickness?: number;
29
+ /** Ring color scheme, aligned with Progress component. */
30
+ colorScheme?: ColorScheme;
31
+ /** Optional custom color overrides. */
32
+ color?: string;
33
+ trackColor?: string;
34
+ className?: string;
35
+ style?: React.CSSProperties;
36
+ /** Optional aria-label when no visible label is adjacent. */
37
+ ariaLabel?: string;
38
+ }) {
39
+ const safeDivisor = dividedBy > 0 ? dividedBy : 1;
40
+ const clampedRaw = clamp(value, 0, safeDivisor);
41
+ const clampedPercent = (clampedRaw / safeDivisor) * 100;
42
+
43
+ // Geometry
44
+ const radius = React.useMemo(() => (size - thickness) / 2, [size, thickness]);
45
+ const circumference = React.useMemo(() => 2 * Math.PI * radius, [radius]);
46
+ const dashOffset = React.useMemo(
47
+ () => ((100 - clampedPercent) / 100) * circumference,
48
+ [circumference, clampedPercent]
49
+ );
50
+
51
+ // Colors: prefer explicit color props, fall back to colorScheme tokens (with safe fallbacks)
52
+ const trackStroke =
53
+ trackColor ?? "var(--n-input-background, rgba(0,0,0,0.08))";
54
+ const colorClass = React.useMemo(() => {
55
+ switch (colorScheme) {
56
+ case "primary":
57
+ return "n-stroke-primary";
58
+ case "secondary":
59
+ return "n-stroke-secondary";
60
+ case "warning":
61
+ return "n-stroke-warning";
62
+ case "normal":
63
+ default:
64
+ return "n-stroke-text";
65
+ }
66
+ }, [colorScheme]);
67
+
68
+ const computedStroke = React.useMemo(() => {
69
+ if (color) return color;
70
+ switch (colorScheme) {
71
+ case "primary":
72
+ return "var(--n-primary, currentColor)";
73
+ case "secondary":
74
+ return "var(--n-secondary, currentColor)";
75
+ case "warning":
76
+ return "var(--n-warning, currentColor)";
77
+ case "normal":
78
+ default:
79
+ return "var(--n-text, currentColor)";
80
+ }
81
+ }, [color, colorScheme]);
82
+
83
+ return (
84
+ <span
85
+ className={cx("n-inline-flex n-items-center n-justify-center", className)}
86
+ style={style}
87
+ role="progressbar"
88
+ aria-valuenow={clampedRaw}
89
+ aria-valuemin={0}
90
+ aria-valuemax={safeDivisor}
91
+ aria-label={ariaLabel}
92
+ >
93
+ <svg
94
+ width={size}
95
+ height={size}
96
+ viewBox={`0 0 ${size} ${size}`}
97
+ style={{ display: "block" }}
98
+ >
99
+ {/* Track */}
100
+ <circle
101
+ cx={size / 2}
102
+ cy={size / 2}
103
+ r={radius}
104
+ fill="none"
105
+ stroke={trackStroke}
106
+ strokeWidth={thickness}
107
+ />
108
+ {/* Indicator */}
109
+ <circle
110
+ cx={size / 2}
111
+ cy={size / 2}
112
+ r={radius}
113
+ fill="none"
114
+ className={cx(
115
+ "n-transition-[stroke-dashoffset] n-duration-500 n-ease-[cubic-bezier(0.65,0,0.35,1)]",
116
+ !color && colorClass
117
+ )}
118
+ style={{ stroke: computedStroke }}
119
+ strokeWidth={thickness}
120
+ strokeLinecap="round"
121
+ strokeDasharray={`${circumference} ${circumference}`}
122
+ strokeDashoffset={dashOffset}
123
+ transform={`rotate(-90 ${size / 2} ${size / 2})`}
124
+ />
125
+ </svg>
126
+ </span>
127
+ );
128
+ }
@@ -14,10 +14,10 @@ export const ScrollArea = React.memo(function ScrollArea({ children }: Props) {
14
14
  React.useState<HTMLDivElement | null>(null);
15
15
 
16
16
  return (
17
- <div className="flex-1 min-h-0">
17
+ <div className="n-flex-1 n-min-h-0">
18
18
  <RadixScrollArea.Root style={{ width: "100%", height: "100%" }}>
19
19
  <RadixScrollArea.Viewport
20
- className="w-full h-full [&>div]:block"
20
+ className="n-w-full n-h-full [&>div]:n-block"
21
21
  ref={React.useCallback(
22
22
  (ref: HTMLDivElement | null) => setScrollElementRef(ref),
23
23
  []
@@ -31,9 +31,9 @@ export const ScrollArea = React.memo(function ScrollArea({ children }: Props) {
31
31
  </RadixScrollArea.Viewport>
32
32
  <RadixScrollArea.Scrollbar
33
33
  orientation="vertical"
34
- className="scroll-component flex p-[3px] data-[orientation=vertical]:w-[10px]"
34
+ className="n-scroll-component n-flex n-p-[3px] data-[orientation=vertical]:n-w-[10px]"
35
35
  >
36
- <RadixScrollArea.Thumb className="scroll-component flex-1 rounded-[10px] bg-scrollbar" />
36
+ <RadixScrollArea.Thumb className="n-scroll-component n-flex-1 n-rounded-[10px] n-bg-scrollbar" />
37
37
  </RadixScrollArea.Scrollbar>
38
38
  </RadixScrollArea.Root>
39
39
  </div>
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { ScrollArea } from "./ScrollArea";
3
+
4
+ export function ScrollableSidebar({ children }: { children: React.ReactNode }) {
5
+ return (
6
+ <div className="n-relative n-flex n-flex-col n-flex-1 n-max-h-full">
7
+ <ScrollArea>{children}</ScrollArea>
8
+ </div>
9
+ );
10
+ }
@@ -155,8 +155,8 @@ export const SearchCompletionMenu = forwardRef(function SearchCompletionMenu(
155
155
  }));
156
156
 
157
157
  return (
158
- <div {...elementSize} className="flex flex-col overflow-hidden">
159
- <InputField.Root className="flex flex-0">
158
+ <div {...elementSize} className="n-flex n-flex-col n-overflow-hidden">
159
+ <InputField.Root className="n-flex n-flex-0">
160
160
  <InputField.Input
161
161
  ref={inputRef}
162
162
  value={search}
@@ -196,7 +196,7 @@ export const SearchCompletionMenu = forwardRef(function SearchCompletionMenu(
196
196
  ) : (
197
197
  <div
198
198
  {...listSize}
199
- className="flex flex-col p-20 items-center justify-center"
199
+ className="n-flex n-flex-col n-p-20 n-items-center n-justify-center"
200
200
  >
201
201
  <Small color="textDisabled">No results</Small>
202
202
  </div>
@@ -3,57 +3,127 @@
3
3
  import {
4
4
  Button,
5
5
  IconButton,
6
+ IconName,
6
7
  IndentContext,
7
8
  INPUT_HEIGHT,
8
9
  InspectorPrimitives,
10
+ renderIcon,
9
11
  Spacer,
12
+ Text,
10
13
  textStyles,
11
14
  } from "@noya-app/noya-designsystem";
12
15
  import { clientStorage, usePersistentStateString } from "@noya-app/react-utils";
13
16
  import React, { CSSProperties, memo, useMemo } from "react";
14
17
 
15
- type TitleIconOptions = {
16
- inlineBlockWrapper?: boolean;
18
+ const titleIconStyle: CSSProperties = {
19
+ marginRight: "6px",
20
+ alignSelf: "flex-start",
21
+ position: "relative",
22
+ display: "flex",
23
+ alignItems: "center",
24
+ minHeight: "27px",
25
+ flex: "none",
17
26
  };
18
27
 
19
- export type SectionProps = {
20
- children: React.ReactNode;
28
+ type SectionHeaderProps = {
29
+ style?: CSSProperties;
30
+ className?: string;
21
31
  title?: React.ReactNode;
22
- onClickTitle?: () => void;
23
32
  titleTextStyle?: "small" | "heading5" | "heading4" | "heading3";
33
+ titleClassName?: string;
34
+ titleIcon?: Exclude<React.ReactNode, string> | IconName;
35
+ onClickTitle?: () => void;
24
36
  right?: React.ReactNode;
37
+ headerSeparator?: "space" | "dot";
38
+ };
39
+
40
+ export function SectionHeader({
41
+ style,
42
+ className,
43
+ title,
44
+ titleIcon,
45
+ right,
46
+ headerSeparator = "space",
47
+ titleTextStyle = "heading4",
48
+ titleClassName,
49
+ onClickTitle,
50
+ }: SectionHeaderProps) {
51
+ const headerStyle: CSSProperties = useMemo(
52
+ () => ({
53
+ minHeight: INPUT_HEIGHT,
54
+ ...style,
55
+ }),
56
+ [style]
57
+ );
58
+
59
+ const titleElement = title ? (
60
+ <InspectorPrimitives.Title
61
+ $textStyle={titleTextStyle}
62
+ className={titleClassName}
63
+ >
64
+ {title}
65
+ </InspectorPrimitives.Title>
66
+ ) : null;
67
+
68
+ return (
69
+ <InspectorPrimitives.SectionHeader
70
+ style={headerStyle}
71
+ className={className}
72
+ >
73
+ {titleIcon && (
74
+ <div style={titleIconStyle} className={textStyles[titleTextStyle]}>
75
+ {"\u200B"}
76
+ {renderIcon(titleIcon)}
77
+ </div>
78
+ )}
79
+ {titleElement && (
80
+ <>
81
+ {onClickTitle ? (
82
+ <Button variant="none" onClick={onClickTitle}>
83
+ {titleElement}
84
+ </Button>
85
+ ) : (
86
+ titleElement
87
+ )}
88
+ </>
89
+ )}
90
+ {headerSeparator === "space" && <Spacer.Horizontal />}
91
+ {headerSeparator === "dot" && (
92
+ <Text
93
+ variant={titleTextStyle}
94
+ color="textDisabled"
95
+ style={{ padding: "0 4px" }}
96
+ >
97
+
98
+ </Text>
99
+ )}
100
+ {right}
101
+ </InspectorPrimitives.SectionHeader>
102
+ );
103
+ }
104
+
105
+ export type SectionProps = {
106
+ children: React.ReactNode;
25
107
  hideRightWhenCollapsed?: boolean;
26
108
  extraPadding?: boolean;
27
109
  className?: string;
28
110
  style?: CSSProperties;
29
- titleIcon?: React.ReactNode;
30
- titleIconOptions?: TitleIconOptions;
31
- };
32
-
33
- const titleIconStyle: CSSProperties = {
34
- marginRight: "8px",
35
- alignSelf: "flex-start",
36
- position: "relative",
37
- top: "2px",
38
- };
39
-
40
- const titleIconWrapperStyle: CSSProperties = {
41
- display: "inline-block",
42
- };
111
+ headerStyle?: CSSProperties;
112
+ } & Omit<SectionHeaderProps, "style" | "className">;
43
113
 
44
114
  const SectionInternal = ({
45
115
  children,
46
116
  title,
47
117
  onClickTitle,
48
- titleTextStyle = "heading4",
118
+ titleTextStyle,
49
119
  right,
50
120
  extraPadding,
51
121
  className,
52
122
  style: styleProp,
53
123
  titleIcon,
54
- titleIconOptions = {
55
- inlineBlockWrapper: true,
56
- },
124
+ headerSeparator,
125
+ titleClassName,
126
+ headerStyle: headerStyleProp,
57
127
  }: SectionProps) => {
58
128
  const style: CSSProperties = useMemo(
59
129
  () => ({
@@ -82,46 +152,26 @@ const SectionInternal = ({
82
152
  const headerStyle: CSSProperties = useMemo(
83
153
  () => ({
84
154
  marginBottom: hasChildren ? "4px" : undefined,
85
- minHeight: INPUT_HEIGHT,
155
+ ...headerStyleProp,
86
156
  }),
87
- [hasChildren]
157
+ [hasChildren, headerStyleProp]
88
158
  );
89
159
 
90
160
  return (
91
161
  <div style={style} className={className}>
92
162
  {(title || titleIcon || right) && (
93
- <InspectorPrimitives.SectionHeader style={headerStyle}>
94
- {titleIcon && (
95
- <div style={titleIconStyle} className={textStyles[titleTextStyle]}>
96
- {titleIconOptions.inlineBlockWrapper ? (
97
- <div style={titleIconWrapperStyle}>{titleIcon}</div>
98
- ) : (
99
- titleIcon
100
- )}
101
- </div>
102
- )}
103
- {title && (
104
- <>
105
- {onClickTitle ? (
106
- <Button variant="none" onClick={onClickTitle}>
107
- <InspectorPrimitives.Title $textStyle={titleTextStyle}>
108
- {title}
109
- </InspectorPrimitives.Title>
110
- </Button>
111
- ) : (
112
- <InspectorPrimitives.Title $textStyle={titleTextStyle}>
113
- {title}
114
- </InspectorPrimitives.Title>
115
- )}
116
- </>
117
- )}
118
- <Spacer.Horizontal />
119
- {right}
120
- </InspectorPrimitives.SectionHeader>
163
+ <SectionHeader
164
+ style={headerStyle}
165
+ title={title}
166
+ titleIcon={titleIcon}
167
+ titleTextStyle={titleTextStyle}
168
+ titleClassName={titleClassName}
169
+ onClickTitle={onClickTitle}
170
+ right={right}
171
+ headerSeparator={headerSeparator}
172
+ />
121
173
  )}
122
- <IndentContext.Provider value={{ indentLevel: 1 }}>
123
- {children}
124
- </IndentContext.Provider>
174
+ <IndentContext.Provider value={0}>{children}</IndentContext.Provider>
125
175
  </div>
126
176
  );
127
177
  };
@@ -148,7 +198,7 @@ const ExpandableSection = ({
148
198
  {...props}
149
199
  right={!props.hideRightWhenCollapsed || expanded ? props.right : null}
150
200
  title={
151
- <div className="flex gap-1 items-center">
201
+ <div className="n-flex n-gap-1 n-items-center">
152
202
  {props.title}
153
203
  <IconButton
154
204
  iconName={expanded ? "ChevronDownIcon2" : "ChevronRightIcon2"}