Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/includes/tags/collapse.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
| --- | --- | --- | --- |
| [accordion] | <code>boolean</code> | <code>true</code> | Works as an accordion |
| [bordered] | <code>string</code> | <code>false</code> | Shows border |
| [open] | <code>boolean</code> | <code>false</code> | Sets default collapsed state |

31 changes: 23 additions & 8 deletions web/libs/editor/src/tags/visual/Collapse.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const { Panel } = Collapse;
* @name Collapse
* @param {boolean} [accordion=true] - Works as an accordion
* @param {string} [bordered=false] - Shows border
* @param {boolean} [open=false] - Sets default collapsed state
*/
const PanelModel = types
.model({
Expand All @@ -32,6 +33,8 @@ const PanelModel = types
_value: types.optional(types.string, ""),
value: types.optional(types.string, ""),

open: types.maybeNull(types.boolean),

children: Types.unionArray([
"view",
"header",
Expand Down Expand Up @@ -101,6 +104,7 @@ const Model = types

bordered: types.optional(types.boolean, false),
accordion: types.optional(types.boolean, true),
open: types.maybeNull(types.boolean),

children: Types.unionArray(["panel"]),
})
Expand All @@ -121,16 +125,27 @@ const CollapseModel = types.compose("CollapseModel", AnnotationMixin, Model, Pro

const HtxCollapse = observer(({ item }) => {
const isBulkMode = isFF(FF_BULK_ANNOTATION) && !isSelfServe() && item.store.hasInterface("annotation:bulk");
const visibleChildren = item.children.filter((i) => i.type === "panel" && (!isBulkMode || i.isIndependent));

// Get default active keys based on both Collapse-level and Panel-level open properties
// Global open sets the base state for all panels
// Local open can override the global state for individual panels
const defaultActiveKeys = visibleChildren.filter((panel) => panel.open ?? item.open).map((c) => `panel-${c.value}`);

// For accordion mode, only the first active key should be used
const finalActiveKeys = item.accordion
? defaultActiveKeys.length > 0
? [defaultActiveKeys[0]]
: []
: defaultActiveKeys;

return (
<Collapse bordered={item.bordered} accordion={item.accordion}>
{item.children
.filter((i) => i.type === "panel" && (!isBulkMode || i.isIndependent))
.map((i) => (
<Panel key={i._value} header={i._value} forceRender>
{Tree.renderChildren(i, item.annotation)}
</Panel>
))}
<Collapse bordered={item.bordered} accordion={item.accordion} defaultActiveKey={finalActiveKeys}>
{visibleChildren.map((c, index) => (
<Panel key={`panel-${c.value}`} header={c._value || c.value || `Panel ${index + 1}`} forceRender>
{Tree.renderChildren(c, item.annotation)}
</Panel>
))}
</Collapse>
);
});
Expand Down
122 changes: 122 additions & 0 deletions web/libs/editor/tests/integration/data/visual_tags/collapse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
export const simpleData = {
text: "This is sample text for testing",
};

// Basic Collapse with default settings
export const basicCollapseConfig = `
<View>
<Collapse>
<Panel value="Panel 1">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;

// Collapse with accordion=false (multiple panels can be open)
export const nonAccordionCollapseConfig = `
<View>
<Collapse accordion="false">
<Panel value="Panel 1">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;

// Collapse with bordered=true
export const borderedCollapseConfig = `
<View>
<Collapse bordered="true">
<Panel value="Panel 1">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;

// Collapse with global open=true (all panels open by default)
export const globalOpenCollapseConfig = `
<View>
<Collapse open="true" accordion="false">
<Panel value="Panel 1">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;

// Collapse with mixed panel-level open states
export const mixedOpenCollapseConfig = `
<View>
<Collapse open="false" accordion="false">
<Panel value="Panel 1" open="true">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2" open="false">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3" open="true">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;

// Collapse with global open=true but some panels override to closed
export const globalOpenWithOverridesConfig = `
<View>
<Collapse open="true" accordion="false">
<Panel value="Panel 1" open="false">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3" open="false">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;

// Collapse with all parameters combined
export const allParamsCollapseConfig = `
<View>
<Collapse accordion="false" bordered="true" open="true">
<Panel value="Panel 1" open="false">
<Text name="text1" value="Content for panel 1" />
</Panel>
<Panel value="Panel 2">
<Text name="text2" value="Content for panel 2" />
</Panel>
<Panel value="Panel 3" open="false">
<Text name="text3" value="Content for panel 3" />
</Panel>
</Collapse>
</View>
`;
Loading
Loading