import {
Cell,
cell,
handler,
ifElse,
lift,
NAME,
navigateTo,
pattern,
UI,
} from "commonfabric";
// the simple piece (to which we'll store references within a cell)
const SimplePattern = pattern(() => ({
[NAME]: "Some Simple Pattern",
[UI]:
Some Simple Pattern
,
}));
// Create a cell to store an array of pieces
const createCellRef = lift(
({ isInitialized, storedCellRef }) => {
if (!isInitialized.get()) {
console.log("Creating cellRef - first time");
const newCellRef = Cell.for("piecesArray");
newCellRef.set([]);
const storedCellValue: Cell = storedCellRef;
storedCellValue.set(newCellRef);
isInitialized.set(true);
return {
cellRef: newCellRef,
};
} else {
console.log("cellRef already initialized");
}
// If already initialized, return the stored cellRef
return {
cellRef: storedCellRef,
};
},
{
type: "object",
properties: {
isInitialized: { type: "boolean", "default": false, asCell: ["cell"] },
storedCellRef: { type: "object", asCell: ["cell"] },
},
required: ["isInitialized", "storedCellRef"],
},
);
// Add a piece to the array and navigate to it
// we get a new isInitialized passed in for each
// piece we add to the list. this makes sure
// we only try to add the piece once to the list
// and we only call navigateTo once
const addPieceAndNavigate = lift(
({ piece, cellRef, isInitialized }) => {
if (!isInitialized.get()) {
if (cellRef) {
cellRef.push(piece);
isInitialized.set(true);
return navigateTo(piece);
} else {
console.log("addPieceAndNavigate undefined cellRef");
}
}
return undefined;
},
{
type: "object",
properties: {
piece: { type: "object" },
cellRef: { type: "array", asCell: ["cell"] },
isInitialized: { type: "boolean", asCell: ["cell"] },
},
required: ["piece", "isInitialized"],
},
);
// Create a new SimplePattern and add it to the array
const createSimplePattern = handler }>(
(_, { cellRef }) => {
// Create isInitialized cell for this piece addition
const isInitialized = cell(false);
// Create the piece
const piece = SimplePattern({});
// Store the piece in the array and navigate
return addPieceAndNavigate({ piece, cellRef, isInitialized });
},
);
// Handler to navigate to a specific piece from the list
const goToPiece = handler(
(_, { piece }) => {
console.log("goToPiece clicked");
return navigateTo(piece);
},
);
// FIXTURE: reactive-cell-map
// Verifies: a reactive factory result still rewrites JSX ifElse predicates after
// the forbidden Reactive cast is removed
// ifElse(!cellRef?.length, ,
) → ifElse(schema..., lift(...)(...), ,
)
// cellRef.map((piece, index) => - ...) → mapWithPattern(...) even with
// `as { cellRef: any[] }`, because the cast does not change the reactive origin
// Context: Real-world pattern using Cell.for(), handler, lift, and navigateTo
// create the named cell inside the pattern body, so we do it just once
export default pattern(() => {
// cell to store array of pieces we created
const { cellRef } = createCellRef({
isInitialized: cell(false),
storedCellRef: cell(),
}) as { cellRef: any[] };
return {
[NAME]: "Pieces Launcher",
[UI]: (
Stored Pieces:
{ifElse(
!cellRef?.length,
No pieces created yet
,
{cellRef.map((piece: any, index: number) => (
-
Go to Piece {index + 1}
Piece {index + 1}: {piece[NAME] || "Unnamed"}
))}
,
)}
Create New Piece
),
cellRef,
};
});