Skip to content

Commit

Permalink
Add methods and callbacks in the Action List control (#355)
Browse files Browse the repository at this point in the history
* Add support to removeItem method in the Action List control

* Add "fixItemCallback" Prop

Callback that is executed when and item requests to be fixed/unfixed.

* Add support to "addItem" method in the Action List control

* Don't fire itemClick if the group's caption is not interactable

* Show additional actions on item focus

* Check if the item still exists before applying removeElement

* Fix addItem implementation
  • Loading branch information
ncamera authored Jul 3, 2024
1 parent 370d6b7 commit 9c13de6
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 10 deletions.
133 changes: 124 additions & 9 deletions src/components/action-list/action-list-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ const defaultSortItemsCallback = (subModel: ActionListItemModel[]): void => {
});
};

// type ImmediateFilter = "immediate" | "debounced" | undefined;

@Component({
tag: "ch-action-list-render",
styleUrl: "action-list-render.scss",
Expand Down Expand Up @@ -206,6 +204,16 @@ export class ChActionListRender {
*/
@Prop() readonly editableItems: boolean = DEFAULT_EDITABLE_ITEMS_VALUE;

/**
* Callback that is executed when and item requests to be fixed/unfixed.
* If the callback is not defined, the item will be fixed/unfixed without
* further confirmation.
*/
@Prop() readonly fixItemCallback?: (
itemInfo: ActionListItemActionable,
newFixedValue: boolean
) => Promise<boolean>;

/**
* This property lets you define the model of the control.
*/
Expand Down Expand Up @@ -377,9 +385,66 @@ export class ChActionListRender {

/**
* Fired when an item is clicked and `selection === "none"`.
* Applies for items that have `type === "actionable"` or
* (`type === "group"` and `expandable === true`)
*/
@Event() itemClick: EventEmitter<ActionListItemModelExtended>;

/**
* Adds an item in the control.
*
* If the item already exists, the operation is canceled.
*
* If the `groupParentId` property is specified the item is added in the
* group determined by `groupParentId`. It only works if the item to add
* has `type === "actionable"`
*/
@Method()
async addItem(
itemInfo: ActionListItemModel,
groupParentId?: string
): Promise<void> {
// Already exists
if (this.#flattenedModel.get(itemInfo.id)) {
return;
}

if (groupParentId) {
const parentGroup = this.#flattenedModel.get(groupParentId);

// The parent group does not exists or it isn't a group
if (
!parentGroup ||
parentGroup.item.type !== "group" ||
itemInfo.type !== "actionable"
) {
return;
}

parentGroup.item.items.push(itemInfo);
this.#flattenedModel.set(itemInfo.id, {
item: itemInfo,
parentItem: parentGroup.item
});

// Sort items in parent model
this.#sortModel(parentGroup.item.items);
}
// Item is placed at the root
else {
this.model.push(itemInfo);
this.#flattenedModel.set(itemInfo.id, {
item: itemInfo,
root: this.model
});

// Sort items in parent model
this.#sortModel(this.model);
}

forceUpdate(this);
}

/**
* Given a list of ids, it returns an array of the items that exists in the
* given list.
Expand All @@ -391,6 +456,29 @@ export class ChActionListRender {
return this.#getItemsInfo(itemsId);
}

/**
* Remove the item and all its descendants from the control.
*/
@Method()
async removeItem(itemId: string) {
const itemUIModel = this.#flattenedModel.get(itemId);

if (!itemUIModel) {
return;
}

// Remove all descendants
if (itemUIModel.item.type === "group") {
const items = itemUIModel.item.items;

items.forEach(item => {
this.#flattenedModel.delete(item.id);
});
}

this.#removeItem(itemUIModel);
}

#getItemsInfo = (itemsId: string[]): ActionListItemModelExtended[] => {
const actionListItemsInfo: ActionListItemModelExtended[] = [];

Expand All @@ -413,7 +501,25 @@ export class ChActionListRender {

const itemUIModel = this.#flattenedModel.get(detail.itemId);
const itemInfo = itemUIModel.item as ActionListItemActionable;
itemInfo.fixed = detail.value;

if (!this.fixItemCallback) {
this.#updateItemFix(itemUIModel, itemInfo, detail.value);
return;
}

this.fixItemCallback(itemInfo, detail.value).then(acceptChange => {
if (acceptChange) {
this.#updateItemFix(itemUIModel, itemInfo, detail.value);
}
});
}

#updateItemFix = (
itemUIModel: ActionListItemModelExtended,
itemInfo: ActionListItemActionable,
newFixedValue: boolean
) => {
itemInfo.fixed = newFixedValue;

// Sort items in parent model
this.#sortModel(
Expand All @@ -423,7 +529,7 @@ export class ChActionListRender {

// Queue a re-render to update the fixed binding and the order of the items
forceUpdate(this);
}
};

@Listen("remove")
onRemove(event: ChActionListItemCustomEvent<string>) {
Expand Down Expand Up @@ -491,6 +597,9 @@ export class ChActionListRender {
const itemInfo = this.#getItemOrGroupInfo(actionListItemOrGroup.id);
this.#checkIfMustExpandCollapseGroup(itemInfo);

if (itemInfo.type === "group" && !itemInfo.expandable) {
return;
}
this.itemClick.emit(this.#flattenedModel.get(itemInfo.id));
};

Expand Down Expand Up @@ -594,15 +703,21 @@ export class ChActionListRender {
const parentArray =
(itemUIModel as ActionListItemModelExtendedRoot).root ??
(itemUIModel as ActionListItemModelExtendedGroup).parentItem.items;
const itemInfo = itemUIModel.item as ActionListItemActionable;
const itemToRemoveId = itemUIModel.item.id;

const itemToRemoveIndex = parentArray.findIndex(
el => (el as ActionListItemActionable).id === itemInfo.id
el => el.id === itemToRemoveId
);

// Remove the UI model from the previous parent. The equality function
// must be by index, not by object reference
removeElement(parentArray, itemToRemoveIndex);
// In some situations, the user could remove the item before the
// "removeItemCallback" promise is resolved
if (itemToRemoveIndex > -1) {
// Remove the UI model from the previous parent. The equality function
// must be by index, not by object reference
removeElement(parentArray, itemToRemoveIndex);
}

this.#flattenedModel.delete(itemToRemoveId);

// Queue a re-render
forceUpdate(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
// - - - - - - - - - - - - - - - - - - - -
// Additional items
// - - - - - - - - - - - - - - - - - - - -
:host(:not(:hover)) .show-on-mouse-hover {
:host(:not(:hover):not(:focus-within)) .show-on-mouse-hover {
display: none;
}

Expand Down

0 comments on commit 9c13de6

Please sign in to comment.