('[data-flat-group-collapsed="true"]');
+ act(() => row?.dispatchEvent(new MouseEvent("click", { bubbles: true })));
+ expect(onToggleOpen).toHaveBeenCalledTimes(1);
+ act(() => root.unmount());
+ });
+});
+
+describe("PinnedZoneDivider", () => {
+ it("renders the 'one open below' label", () => {
+ const { host, root } = renderInto();
+ expect(host.textContent).toContain("one open below");
+ act(() => root.unmount());
+ });
+});
diff --git a/packages/studio/src/components/editor/propertyPanelFlatPrimitives.tsx b/packages/studio/src/components/editor/propertyPanelFlatPrimitives.tsx
index 5acd863ff..067ecb7a7 100644
--- a/packages/studio/src/components/editor/propertyPanelFlatPrimitives.tsx
+++ b/packages/studio/src/components/editor/propertyPanelFlatPrimitives.tsx
@@ -131,3 +131,105 @@ export function FlatSegmentedRow({
);
}
+
+/* ------------------------------------------------------------------ */
+/* FlatGroup — one-open-at-a-time accordion group (controlled) */
+/* ------------------------------------------------------------------ */
+
+export function FlatGroup({
+ title,
+ isOpen,
+ isPinned,
+ onToggleOpen,
+ onTogglePin,
+ accessory,
+ summary,
+ children,
+}: {
+ title: string;
+ isOpen: boolean;
+ isPinned: boolean;
+ onToggleOpen: () => void;
+ onTogglePin: () => void;
+ accessory?: ReactNode;
+ summary?: string;
+ children: ReactNode;
+}) {
+ if (!isOpen) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
{title}
+
+ {accessory}
+
+
+
+
+ {children}
+
+ );
+}
+
+/* ------------------------------------------------------------------ */
+/* PinnedZoneDivider */
+/* ------------------------------------------------------------------ */
+
+export function PinnedZoneDivider() {
+ return (
+
+
+
+ one open below
+
+
+
+ );
+}