addItems method
Adds multiple items.
When parentKey is provided, items are added as children of that parent.
Throws ArgumentError if any key already exists or if parentKey is unknown.
Implementation
void addItems(List<T> newItems, {K? parentKey, bool prepend = true}) {
if (newItems.isEmpty) return;
TListItem<T, K>? parent;
if (parentKey != null) {
parent = _itemsMap[parentKey];
if (parent == null) {
throw ArgumentError.value(parentKey, 'parentKey', 'Provided parent key does not exist');
}
}
final level = parent != null ? parent.level + 1 : 0;
// Validate all keys up front so a duplicate-key throw mid-loop can't leave
// _itemsMap partially mutated (atomicity guarantee).
for (final item in newItems) {
final key = itemKey(item);
if (_itemsMap.containsKey(key)) {
throw ArgumentError.value(key, 'key', 'Item already exists');
}
}
final newElements = [
for (final item in newItems) _registerRecursive(item, parentKey: parent?.key, level: level, prepend: prepend),
];
// Keep the parent's childrenKeys in sync — without this, expansion/descendant
// traversal never discovers the new items.
if (parent != null) {
final newKeys = newElements.map((e) => e.key).toList();
final existing = parent.childrenKeys ?? const [];
// Avoid spread-into-list — on web (DDC) spreads can produce JSArray<dynamic>.
final merged = <K>[];
if (prepend) {
merged.addAll(newKeys);
merged.addAll(existing);
} else {
merged.addAll(existing);
merged.addAll(newKeys);
}
_itemsMap[parent.key] = itemFactory(parent.data, parentKey: parent.parentKey, childrenKeys: merged, level: parent.level);
// Sync the updated parent back into _localPaginationItems and displayItems.
_syncParentInLocalAndDisplay(parent.key);
}
final newDisplayItems = _spliceNewItems(parent, newElements, prepend);
updateState(who: 'addItems', displayItems: newDisplayItems, totalItems: value.totalItems + newItems.length);
}