Skip to content
Open
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
6 changes: 4 additions & 2 deletions packages/sanity/flutter_sanity_portable_text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,10 @@ class MyApp extends StatelessWidget {
Widget columnBuilder(BuildContext context, List<PortableBlockItem> blocks) {
return Column(
children: blocks
.map(
(block) => PortableTextConfig.shared.buildBlock(context, block))
.asMap()
.entries
.map((entry) =>
PortableTextConfig.shared.buildBlock(context, entry.value, entry.key))
.toList(),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ class PortableTextBlock extends StatelessWidget {
/// The model representing the block of Portable Text.
final TextBlockItem model;

const PortableTextBlock({super.key, required this.model});
/// The position of this block within its parent list (0-based). Passed on to
/// the [BlockContainerBuilder] so containers can vary by position (e.g. drop
/// leading space on the first block). Defaults to 0 for standalone use.
final int index;

const PortableTextBlock({super.key, required this.model, this.index = 0});

@override
Widget build(final BuildContext context) {
Expand All @@ -36,7 +41,7 @@ class PortableTextBlock extends StatelessWidget {
final builder = config.blockContainers[model.style] ??
PortableTextConfig.defaultBlockContainerBuilder;

final child = builder(context, content);
final child = builder(context, content, index);

final leftPadding =
model.listItem == null ? 0.0 : config.listIndent * (model.level ?? 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,23 @@ typedef TextStyleBuilder = TextStyle Function(
);

/// A function that builds a widget for a Portable block container.
typedef BlockContainerBuilder = Widget Function(BuildContext, Widget);
///
/// [index] is the position of the block within its parent list (0-based), which
/// lets containers vary by position — e.g. suppressing leading space on the
/// first block.
typedef BlockContainerBuilder = Widget Function(
BuildContext context,
Widget child,
int index,
);

/// A function that builds a widget for a Portable block item.
///
/// [index] is the position of the block within its parent list (0-based).
typedef BlockWidgetBuilder = Widget Function(
BuildContext context,
PortableBlockItem item,
int index,
);

/// A function that builds an InlineSpan for a single bullet mark. Using the
Expand Down Expand Up @@ -97,15 +108,19 @@ final class PortableTextConfig {
/// Builds a block widget for the given Portable block item.
/// The block widget is determined by the block type of the item. If the block type is not found in the
/// block widgets, an error view is rendered with a message indicating the missing block type.
Widget buildBlock(final BuildContext context, final PortableBlockItem item) {
Widget buildBlock(
final BuildContext context,
final PortableBlockItem item,
final int index,
) {
final type = item.blockType;

final builder = blocks[type];
if (builder == null) {
return ErrorView(message: 'Missing builder for block "$type"');
}

return builder(context, item);
return builder(context, item, index);
}

/// Resets the shared instance of the [PortableTextConfig] to the default configuration.
Expand Down Expand Up @@ -167,7 +182,7 @@ final class PortableTextConfig {
}

static BlockContainerBuilder defaultBlockContainerBuilder =
(final BuildContext context, final Widget child) {
(final BuildContext context, final Widget child, final int index) {
return child;
};

Expand Down Expand Up @@ -269,7 +284,8 @@ final class PortableTextConfig {

/// The default block containers used by the shared instance of [PortableTextConfig].
static final Map<String, BlockContainerBuilder> defaultBlockContainers = {
'blockquote': (final BuildContext context, final Widget child) {
'blockquote':
(final BuildContext context, final Widget child, final int index) {
final theme = Theme.of(context);

return Container(
Expand All @@ -293,8 +309,9 @@ final class PortableTextConfig {
/// The default block widgets used by the shared instance of [PortableTextConfig].
/// The default block is a single [PortableTextBlock], named as "block".
static final Map<String, BlockWidgetBuilder> defaultBlocks = {
'block': (final context, final item) => PortableTextBlock(
'block': (final context, final item, final index) => PortableTextBlock(
model: item as TextBlockItem,
index: index,
),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ Widget defaultListBuilder(
itemCount: blocks.length,
padding: EdgeInsets.zero,
itemBuilder: (final context, final index) =>
PortableTextConfig.shared.buildBlock(context, blocks[index]),
PortableTextConfig.shared.buildBlock(context, blocks[index], index),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ void main() {
testWidgets('PortableText can apply a custom block',
(WidgetTester tester) async {
PortableTextConfig.shared.blocks[_CustomBlockItem.schemaName] =
(context, item) {
(context, item, index) {
return const Text('Hello, World');
};

Expand All @@ -91,7 +91,7 @@ void main() {
return const TextStyle(color: Colors.red);
};
PortableTextConfig.shared.blockContainers['custom-block'] =
(context, child) {
(context, child, index) {
return Container(
color: Colors.red,
child: child,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ void main() {
Widget columnBuilder(BuildContext context, List<PortableBlockItem> blocks) {
return Column(
children: blocks
.map(
(block) => PortableTextConfig.shared.buildBlock(context, block))
.asMap()
.entries
.map((entry) => PortableTextConfig.shared
.buildBlock(context, entry.value, entry.key))
.toList(),
);
}
Expand Down