Skip to content

Commit

Permalink
🐞 fix: Fix the issue where material properties cannot be synchronized
Browse files Browse the repository at this point in the history
  • Loading branch information
xiangechen committed Jan 3, 2025
1 parent b7a2b28 commit 1088c4e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 42 deletions.
6 changes: 4 additions & 2 deletions packages/chili-core/src/foundation/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export type CollectionChangedArgs =
}
| {
action: CollectionAction.replace;
item: any;
index: number;
item: any,
items: any[];
};

Expand Down Expand Up @@ -105,6 +106,7 @@ export class ObservableCollection<T> implements ICollectionChanged, IDisposable
this._callbacks.forEach((callback) =>
callback({
action: CollectionAction.replace,
index,
item,
items,
}),
Expand Down Expand Up @@ -143,7 +145,7 @@ export class ObservableCollection<T> implements ICollectionChanged, IDisposable
return this._items.find(predicate);
}

indexOf(item: T, fromIndex: number | undefined) {
indexOf(item: T, fromIndex?: number) {
return this._items.indexOf(item, fromIndex);
}

Expand Down
25 changes: 13 additions & 12 deletions packages/chili-ui/src/components/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import { HTMLProps } from "./htmlProps";

export type CollectionProps<T> = HTMLProps<Collection<T>> & {
sources: ObservableCollection<T> | Array<T>;
template: (item: T) => HTMLElement | SVGSVGElement;
template: (item: T, index: number) => HTMLElement | SVGSVGElement;
};

export class Collection<T> extends HTMLElement {
private _itemMap = new Map<T, HTMLElement | SVGSVGElement>();
private readonly _itemMap = new Map<T, HTMLElement | SVGSVGElement>();
constructor(readonly props: CollectionProps<T>) {
super();
setProperties(this, props as any);
}

getItem(item: any): HTMLElement | SVGSVGElement | undefined {
getItem(item: T): HTMLElement | SVGSVGElement | undefined {
return this._itemMap.get(item);
}

Expand All @@ -34,15 +34,15 @@ export class Collection<T> extends HTMLElement {
this.props.sources.removeCollectionChanged(this._onCollectionChanged);
}

private _onCollectionChanged = (args: CollectionChangedArgs) => {
private readonly _onCollectionChanged = (args: CollectionChangedArgs) => {
if (args.action === CollectionAction.add) {
this.append(...this._mapItems(args.items));
} else if (args.action === CollectionAction.remove) {
this._removeItem(args.items);
} else if (args.action === CollectionAction.move) {
this._moveItem(args.from, args.to);
} else if (args.action === CollectionAction.replace) {
this._replaceItem(args.item, args.items);
this._replaceItem(args.index, args.item, args.items);
} else {
throw new Error("Unknown collection action");
}
Expand All @@ -54,28 +54,29 @@ export class Collection<T> extends HTMLElement {
if (item1 && item2) this.insertBefore(item1, item2);
}

private _replaceItem(item: any, items: any[]) {
private _replaceItem(index: number, item: T, items: T[]) {
let child = this._itemMap.get(item);
if (child) {
items.forEach((item) => {
let e = this.props.template(item);
items.forEach((item, i) => {
let e = this.props.template(item, index + i);
this._itemMap.set(item, e);
this.insertBefore(e, child);
});
this._removeItem([item]);
}
}

private _mapItems(items: any[]) {
return items.map((item) => {
private _mapItems(items: T[]) {
let index = this._itemMap.size;
return items.map((item, i) => {
if (this._itemMap.has(item)) return this._itemMap.get(item)!;
let e = this.props.template(item);
let e = this.props.template(item, index + i);
this._itemMap.set(item, e);
return e;
});
}

private _removeItem(items: any[]) {
private _removeItem(items: T[]) {
items.forEach((item) => {
if (this._itemMap.has(item)) {
this._itemMap.get(item)?.remove();
Expand Down
58 changes: 30 additions & 28 deletions packages/chili-ui/src/property/materialProperty.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,29 @@
// Copyright 2022-2023 the Chili authors. All rights reserved. AGPL-3.0 license.

import { Binding, IDocument, Material, PathBinding, Property, PubSub, Transaction } from "chili-core";
import { button, div, localize, span } from "../components";
import { Binding, IDocument, Material, ObservableCollection, PathBinding, Property, PubSub, Transaction } from "chili-core";
import { button, collection, div, localize, span } from "../components";
import style from "./materialProperty.module.css";
import { PropertyBase } from "./propertyBase";
import { UrlStringConverter } from "./material/urlConverter";
import { ColorConverter } from "../converters";

export class MaterialProperty extends PropertyBase {
private readonly materials: ObservableCollection<Material>

constructor(
readonly document: IDocument,
objects: { materialId: string | string[] }[],
readonly property: Property,
) {
super(objects);
if (Array.isArray(objects[0].materialId)) {
if (objects[0].materialId.length === 1) {
this.append(this.materialControl(document, objects[0].materialId[0]));
} else {
for (let i = 0; i < objects[0].materialId.length; i++) {
this.append(this.materialControl(document, objects[0].materialId[i], i + 1));
}
}
} else {
this.append(this.materialControl(document, objects[0].materialId));
}
this.materials = this.materialCollection(objects[0].materialId);
this.append(collection({
sources: this.materials,
template: (material, index) => this.materialControl(document, material, index),
}))
}

private materialControl(document: IDocument, materialId: string, index?: number) {
let material = this.findMaterial(materialId);
if (!material) {
return "";
}

private materialControl(document: IDocument, material: Material, index: number) {
return div(
{
className: style.material,
Expand All @@ -41,7 +32,7 @@ export class MaterialProperty extends PropertyBase {
span({
textContent: localize("common.material"),
}),
index ? span({ textContent: " " + index.toString() }) : "",
this.materials.length > 1 ? span({ textContent: ` ${index + 1}`}) : "",
),
button({
textContent: material.name,
Expand All @@ -61,15 +52,14 @@ export class MaterialProperty extends PropertyBase {
);
}

private setMaterial(e: MouseEvent, material: Material, index?: number) {
let button = e.target as HTMLButtonElement;
button.textContent = material.name;
private setMaterial(e: MouseEvent, material: Material, index: number) {
Transaction.excute(this.document, "change material", () => {
this.materials.replace(index, material);
this.objects.forEach((x) => {
if (this.property.name in x) {
if (index) {
x.materialId = x.materialId.toSpliced(index - 1, 1, material.id);
} else {
if (this.materials.length > 1) {
x.materialId = x.materialId.toSpliced(index, 1, material.id);
} else if (this.materials.length === 1) {
x.materialId = material.id;
}
}
Expand All @@ -78,8 +68,20 @@ export class MaterialProperty extends PropertyBase {
this.document.visual.update();
}

private findMaterial(id: string) {
return this.document.materials.find((x) => x.id === id);
private materialCollection(id: string | string[]) {
const findMaterial = (id: string) => this.document.materials.find(m => m.id === id);

let materials: Material[]
if (Array.isArray(id)) {
materials = id.map((x) => findMaterial(x)).filter((x) => x !== undefined);
} else {
materials = [];
let material = findMaterial(id);
if (material) {
materials.push(material);
}
}
return new ObservableCollection(...materials);
}
}

Expand Down

0 comments on commit 1088c4e

Please sign in to comment.