Skip to content

Commit

Permalink
replace mutateClasses with setClass
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanJablo committed Dec 10, 2024
1 parent df4f570 commit ae2c32a
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3202,13 +3202,10 @@ describe('classes property', () => {
});

$forEachSelectedTextNode((textNode) => {
textNode.mutateClasses((classes) => {
classes.bg = 'red';
classes.active = true;
classes.highlight = 'yellow';
// @ts-expect-error - just testing what happens if someone ignores the type
classes.disabled = false;
});
textNode.setClass('bg', 'red');
textNode.setClass('active', true);
textNode.setClass('highlight', 'yellow');
textNode.setClass('disabled', false);
});
});

Expand Down Expand Up @@ -3238,16 +3235,9 @@ describe('classes property', () => {

// should ignore false, numbers or undefined
await editor.update(() => {
p.mutateClasses((classes) => {
classes.bg = 'red';
classes.active = true;
// @ts-expect-error - just testing what happens if someone ignores the type
classes.highlight = false;
// @ts-expect-error - just testing what happens if someone ignores the type
classes.someNumber = 4;
// @ts-ignore
classes.somethingUndefined = undefined;
});
p.setClass('bg', 'red');
p.setClass('active', true);
p.setClass('highlight', false);
});
expect('classes' in getSerializedParagraph(editor)).toBe(true);
expect(getSerializedParagraph(editor).classes).toStrictEqual({
Expand All @@ -3257,10 +3247,8 @@ describe('classes property', () => {

// should not export classes if empty
await editor.update(() => {
p.mutateClasses((classes) => {
delete classes.bg;
delete classes.active;
});
p.setClass('bg', false);
p.setClass('active', false);
});
expect('classes' in getSerializedParagraph(editor)).toBe(false);
});
Expand Down
12 changes: 2 additions & 10 deletions packages/lexical/src/LexicalEditorState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,8 @@ function exportNodeToJSON<SerializedNode extends SerializedLexicalNode>(
node: LexicalNode,
): SerializedNode {
const serializedNode = node.exportJSON();
if (node.__classes) {
const classes = Object.fromEntries(
Object.entries(node.__classes).filter(
([_, value]: [string, unknown]) =>
typeof value === 'string' || (typeof value === 'boolean' && value),
),
);
if (Object.keys(classes).length > 0) {
serializedNode.classes = classes;
}
if (node.__classes && Object.keys(node.__classes).length > 0) {
serializedNode.classes = node.__classes;
}
const nodeClass = node.constructor;

Expand Down
41 changes: 25 additions & 16 deletions packages/lexical/src/LexicalNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type NodeMap = Map<NodeKey, LexicalNode>;
export type SerializedLexicalNode = {
type: string;
version: number;
classes?: ReadOnlyClasses;
classes?: ReadonlyClasses;
};

/** @internal */
Expand Down Expand Up @@ -172,7 +172,7 @@ export type DOMExportOutput = {

export type NodeKey = string;
export type MutableClasses = {[classSuffix: string]: true | string};
export type ReadOnlyClasses = {readonly [classSuffix: string]: true | string};
export type ReadonlyClasses = {readonly [classSuffix: string]: true | string};

export class LexicalNode {
// Allow us to look up the type including static props
Expand All @@ -192,7 +192,7 @@ export class LexicalNode {
* Don't use this directly, use `this.getClasses()` and `this.mutateClasses()` instead
* @internal
*/
__classes?: ReadOnlyClasses;
__classes?: ReadonlyClasses;

/**
* Returns an object of classes in the form of `prefix-suffix` for string values, or just `prefix` for true boolean values.
Expand All @@ -206,27 +206,36 @@ export class LexicalNode {
*
* @returns The classes object.
*/
getClasses(): ReadOnlyClasses {
getClasses(): ReadonlyClasses {
const self = this.getLatest();
return self.__classes || {};
return {...self.__classes};
}

/**
* Allows mutation of the classes object where the key-value pairs follow the format `prefix-suffix` for string values,
* or just `prefix` for true boolean values.
* Sets a class based on the provided key and value.
*
* @example
* node.mutateClasses((currentClasses) => {
* currentClasses.bg = 'blue'; // the node will now be rendered with class `bg-blue`
* delete currentClasses.active; // the node will no longer have the class `active`
* });
* @param key - The class key to set or modify.
* @param value - The class value. Possible options:
* - `true`: add the class if it doesn't exist.
* - `false`: remove the class if it exists.
* - `string`: Adds a class in the format `key-value` (e.g., `bg-blue`), useful for overwriting existing classes with the same key.
*
* @param fn A function that receives the current classes object and allows it to be mutated safely.
* @example
* node.setClass('active', true); // Adds the class `active`, replacing the one with the key `active` if it exists.
* node.setClass('active', false); // Removes any class with the key `active` (e.g., `active` or `active-blue`).
* node.setClass('bg', 'blue'); // Adds the class `bg-blue`
*/
mutateClasses(fn: (classes: MutableClasses) => void) {
setClass(key: string, value: boolean | string) {
const self = this.getWritable();
self.__classes = self.__classes || {};
fn(self.__classes);
const classes = {...self.__classes};
if (value === false) {
delete classes[key];
} else {
classes[key] = value;
}
if (Object.keys(classes).length > 0) {
self.__classes = classes;
}
}

// Flow doesn't support abstract classes unfortunately, so we can't _force_
Expand Down
4 changes: 2 additions & 2 deletions packages/lexical/src/LexicalUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import type {SerializedEditorState} from './LexicalEditorState';
import type {
LexicalNode,
ReadOnlyClasses,
ReadonlyClasses,
SerializedLexicalNode,
} from './LexicalNode';

Expand Down Expand Up @@ -342,7 +342,7 @@ type InternalSerializedNode = {
children?: Array<InternalSerializedNode>;
type: string;
version: number;
classes?: ReadOnlyClasses;
classes?: ReadonlyClasses;
};

export function $parseSerializedNode(
Expand Down
4 changes: 2 additions & 2 deletions packages/lexical/src/nodes/LexicalTextNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ export class TextNode extends LexicalNode {
writableNode = $createTextNode(firstPart);
writableNode.__format = format;
writableNode.__style = style;
writableNode.__classes = {...classes};
writableNode.__classes = classes;
writableNode.__detail = detail;
hasReplacedSelf = true;
} else {
Expand All @@ -978,7 +978,7 @@ export class TextNode extends LexicalNode {
const sibling = $createTextNode(part).getWritable();
sibling.__format = format;
sibling.__style = style;
sibling.__classes = {...classes};
sibling.__classes = classes;
sibling.__detail = detail;
const siblingKey = sibling.__key;
const nextTextSize = textSize + partSize;
Expand Down

0 comments on commit ae2c32a

Please sign in to comment.