-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Allow StructBlocks to be collapsible #13216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow StructBlocks to be collapsible #13216
Conversation
f4cba86
to
9d31077
Compare
@@ -26,18 +26,35 @@ You can then provide custom CSS for this block, targeted at the specified classn | |||
Wagtail's editor styling has some built-in styling for the `struct-block` class and other related elements. If you specify a value for `form_classname`, it will overwrite the classes that are already applied to `StructBlock`, so you must remember to specify the `struct-block` as well. | |||
``` | |||
|
|||
In addition, the `StructBlock`'s `Meta` class also accepts a `collapsed` attribute. When set to `None` (the default), the block is not collapsible. When set to `True` or `False`, the block is wrapped in a collapsible panel and initially displayed in a collapsed or expanded state in the editing interface, respectively. This can be useful for blocks with many sub-blocks, or blocks that are not expected to be edited frequently. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not 100% sure on this API design, but this allows us to mirror the collapsed
option on StreamBlock
and ListBlock
, while keeping the current behaviour of any existing StructBlock
s (i.e. collapsed = None
).
We can't make StructBlock
s collapsible by default, as this means they'd have two collapsible wrappers when used in StreamBlock
or ListBlock
, unless we want to handle that case specifically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that’s the right approach. Definitely should consider making StructBlock collapsible by default IMO, in which case yes this would be worth adding extra logic to handle. But not in this PR!
9d31077
to
08ed045
Compare
The class name passed as `form_classname` (defaults to `struct-block`). | ||
|
||
**`block_definition`** | ||
**`collapsed`**\ | ||
The initial collapsible state of the block (defaults to `None`). Note that the collapsible panel wrapper is not automatically applied to the block's form template. You must write your own wrapper if you want the block to be collapsible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not 100% sure either. We could wrap the custom form template in the collapsible section if that's desired, but it means we have to handle both cases in the StructBlock
rendering logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All working well! A few things I’d nitpick in the implementation and there seems to be one or two bugs that were in this code before:
- Toggle’s
aria-expanded
always set totrue
in initial rendering. I’ve not changed that yet as we also have the issue everywhere else. If you agree the code is off, could you open a follow-up issue? - Translation support for the
aria-label
. Will pick that up while merging.
@@ -2,6 +2,7 @@ import $ from 'jquery'; | |||
import { FieldBlockDefinition } from './FieldBlock'; | |||
import { StreamBlockDefinition } from './StreamBlock'; | |||
import { StructBlockDefinition } from './StructBlock'; | |||
import { initCollapsiblePanels } from '../../../includes/panels'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t see this being used anywhere?
wagtail/tests/test_blocks.py
Outdated
block.set_name("test_structblock") | ||
js_args = StructBlockAdapter().js_args(block) | ||
|
||
self.assertIs(js_args[2].get("collapsed"), case) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noting as far as I can see all other unit tests for js_args
’ meta
directly access the attributes (js_args[2]["collapsed"]
). And I believe collapsed
is always returned? So could be nice to switch for consistency.
|
||
test('setError shows non-block errors', () => { | ||
boundBlock.setError({ | ||
messages: ['This is just generally wrong.'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔥
<use href="#icon-link"></use> | ||
</svg> | ||
</a> | ||
<button class="w-panel__toggle" type="button" aria-label="${'Toggle section'}" aria-describedby="${headingId}" data-panel-toggle aria-controls="${contentId}" aria-expanded="true"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, not specific to your changes but shouldn’t this aria-expanded
be toggled between true
and false
based on the collapsed
state?
blockTypeIcon, | ||
blockTypeLabel, | ||
collapsed, | ||
} = this.props; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh no, he’s reinvented React!
// Keep in sync with wagtailadmin/shared/panel.html | ||
template.innerHTML = /* html */ ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder at what point we need this so many times that we should find a better technique.
<use href="#icon-link"></use> | ||
</svg> | ||
</a> | ||
<button class="w-panel__toggle" type="button" aria-label="${'Toggle section'}" aria-describedby="${headingId}" data-panel-toggle aria-controls="${contentId}" aria-expanded="true"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh-oh, we missed the un-translateable Toggle section
</div> | ||
</section> | ||
`; | ||
return template.content.firstElementChild as HTMLElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh TypeScript
@@ -26,18 +26,35 @@ You can then provide custom CSS for this block, targeted at the specified classn | |||
Wagtail's editor styling has some built-in styling for the `struct-block` class and other related elements. If you specify a value for `form_classname`, it will overwrite the classes that are already applied to `StructBlock`, so you must remember to specify the `struct-block` as well. | |||
``` | |||
|
|||
In addition, the `StructBlock`'s `Meta` class also accepts a `collapsed` attribute. When set to `None` (the default), the block is not collapsible. When set to `True` or `False`, the block is wrapped in a collapsible panel and initially displayed in a collapsed or expanded state in the editing interface, respectively. This can be useful for blocks with many sub-blocks, or blocks that are not expected to be edited frequently. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that’s the right approach. Definitely should consider making StructBlock collapsible by default IMO, in which case yes this would be worth adding extra logic to handle. But not in this PR!
08ed045
to
d8d7b12
Compare
Screen.Recording.2025-07-09.at.16.57.08.mov
Alternative to #2299.
To test: