Skip to content

Commit d974b92

Browse files
committed
feat(json-crdt-peritext-ui): 🎸 move new slice config state into the toolbar plugin
1 parent 7ede446 commit d974b92

File tree

7 files changed

+63
-67
lines changed

7 files changed

+63
-67
lines changed

‎src/json-crdt-extensions/peritext/editor/Editor.ts‎

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import {isLetter, isPunctuation, isWhitespace, stepsEqual} from './util';
1212
import {ValueSyncStore} from '../../../util/events/sync-store';
1313
import {MarkerOverlayPoint} from '../overlay/MarkerOverlayPoint';
1414
import {UndefEndIter, type UndefIterator} from '../../../util/iterator';
15-
import {s, tick, Timespan, type ITimespanStruct} from '../../../json-crdt-patch';
15+
import {tick, Timespan, type ITimespanStruct} from '../../../json-crdt-patch';
1616
import {CursorAnchor, SliceBehavior, SliceHeaderMask, SliceHeaderShift, SliceTypeCon} from '../slice/constants';
17-
import {Model, ObjApi} from '../../../json-crdt/model';
1817
import type {Point} from '../rga/Point';
1918
import type {Range} from '../rga/Range';
2019
import type {Printable} from 'tree-dump';
@@ -31,10 +30,7 @@ import type {
3130
ViewSlice,
3231
EditorUi,
3332
EditorSelection,
34-
SliceConfigState,
3533
} from './types';
36-
import type {ObjNode} from '../../../json-crdt/nodes';
37-
import type {SliceRegistryEntry} from '../registry/SliceRegistryEntry';
3834

3935
/**
4036
* For inline boolean ("Overwrite") slices, both range endpoints should be
@@ -54,19 +50,6 @@ const makeRangeExtendable = <T>(range: Range<T>): void => {
5450
}
5551
};
5652

57-
class NewSliceConfig<Node extends ObjNode = ObjNode> implements SliceConfigState<Node> {
58-
public readonly model: Model<ObjNode<{conf: any}>>;
59-
60-
constructor(public readonly def: SliceRegistryEntry) {
61-
const schema = s.obj({conf: def.schema || s.con(void 0)});
62-
this.model = Model.create(schema);
63-
}
64-
65-
public conf(): ObjApi<Node> {
66-
return this.model.api.obj(['conf']) as ObjApi<Node>;
67-
}
68-
}
69-
7053
export class Editor<T = string> implements Printable {
7154
public readonly saved: EditorSlices<T>;
7255
public readonly extra: EditorSlices<T>;
@@ -86,12 +69,6 @@ export class Editor<T = string> implements Printable {
8669
*/
8770
public readonly pending = new ValueSyncStore<Map<CommonSliceType | string | number, unknown> | undefined>(void 0);
8871

89-
/**
90-
* New slice configuration. This is used for new slices which are not yet
91-
* applied to the text as they need to be configured first.
92-
*/
93-
public readonly newSliceConfig = new ValueSyncStore<NewSliceConfig | undefined>(void 0);
94-
9572
constructor(public readonly txt: Peritext<T>) {
9673
this.saved = new EditorSlices(txt, txt.savedSlices);
9774
this.extra = new EditorSlices(txt, txt.extraSlices);
@@ -764,18 +741,6 @@ export class Editor<T = string> implements Printable {
764741
}
765742
}
766743

767-
public startSliceConfig(tag: SliceTypeCon | string | number): NewSliceConfig | undefined {
768-
const entry = this.getRegistry().get(tag);
769-
const newSliceConfig = this.newSliceConfig;
770-
if (!entry) {
771-
newSliceConfig.next(void 0);
772-
return;
773-
}
774-
const configState = new NewSliceConfig(entry);
775-
newSliceConfig.next(configState);
776-
return configState;
777-
}
778-
779744
// --------------------------------------------------------- block formatting
780745

781746
/**

‎src/json-crdt-extensions/peritext/editor/types.ts‎

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import type {ObjApi} from '../../../json-crdt/model';
2-
import type {ObjNode} from '../../../json-crdt/nodes';
31
import type {UndefIterator} from '../../../util/iterator';
4-
import type {SliceRegistryEntry} from '../registry/SliceRegistryEntry';
52
import type {Point} from '../rga/Point';
63
import type {Range} from '../rga/Range';
74
import type {SliceType} from '../slice';
@@ -55,19 +52,3 @@ export interface EditorUi<T = string> {
5552
*/
5653
vert?(point: Point<T>, steps: number): Point<T> | undefined;
5754
}
58-
59-
/**
60-
* Transient UI configuration state of a slice. Used to render to the user
61-
* slice configuration UI, such as popups, modals, etc.
62-
*/
63-
export interface SliceConfigState<Node extends ObjNode = ObjNode> {
64-
/** Slice definition in the registry. */
65-
def: SliceRegistryEntry;
66-
67-
/**
68-
* An object representing the actual configuration of this slice instance.
69-
* This object is either already stored in the document, or will be stored
70-
* when the user commits the changes.
71-
*/
72-
conf(): ObjApi<Node>;
73-
}

‎src/json-crdt-peritext-ui/events/defaults/PeritextEventDefaults.ts‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,7 @@ export class PeritextEventDefaults implements PeritextEventHandlerMap {
196196
switch (behavior) {
197197
case 'many': {
198198
if (tag === undefined) throw new Error('TYPE_REQUIRED');
199-
const entry = editor.getRegistry().get(tag);
200-
const isConfigurable = !!entry?.schema;
201-
if (isConfigurable) {
202-
editor.startSliceConfig(tag);
203-
} else {
204-
slices.insStack(tag, data, selection);
205-
}
199+
slices.insStack(tag, data, selection);
206200
break;
207201
}
208202
case 'one': {

‎src/json-crdt-peritext-ui/plugins/toolbar/cursor/RenderFocus.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ export const RenderFocus: React.FC<RenderFocusProps> = ({children, cursor}) => {
1616
const showInlineToolbar = toolbar.showInlineToolbar;
1717
const [showInlineToolbarValue, toolbarVisibilityChangeTime] = useSyncStore(showInlineToolbar);
1818
const enableAfterCoolDown = useTimeout(300, [toolbarVisibilityChangeTime]);
19-
const isScrubbing = useSyncStoreOpt(toolbar.surface.dom?.cursor.mouseDown) || false;
20-
const newSliceConfig = useSyncStore(surface.peritext.editor.newSliceConfig);
21-
// const focus = useSyncStoreOpt(toolbar.surface.dom?.cursor.focus) || false;
19+
const isScrubbing = useSyncStoreOpt(surface.dom?.cursor.mouseDown) || false;
20+
const newSliceConfig = useSyncStore(toolbar.newSliceConfig);
21+
// const focus = useSyncStoreOpt(surface.dom?.cursor.focus) || false;
2222
// const blurTimeout = useTimeout(300, [focus]);
2323

2424
const handleClose = React.useCallback(() => {
25-
// toolbar.surface.dom?.focus();
25+
// surface.dom?.focus();
2626
// // if (showInlineToolbar.value) showInlineToolbar.next(false);
2727
}, []);
2828

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {s} from '../../../../json-crdt-patch';
2+
import {Model, ObjApi} from '../../../../json-crdt/model';
3+
import type {SliceRegistryEntry} from '../../../../json-crdt-extensions/peritext/registry/SliceRegistryEntry';
4+
import type {SliceConfigState} from './types';
5+
import type {ObjNode} from '../../../../json-crdt/nodes';
6+
7+
export class NewSliceConfig<Node extends ObjNode = ObjNode> implements SliceConfigState<Node> {
8+
public readonly model: Model<ObjNode<{conf: any}>>;
9+
10+
constructor(public readonly def: SliceRegistryEntry) {
11+
const schema = s.obj({conf: def.schema || s.con(void 0)});
12+
this.model = Model.create(schema);
13+
}
14+
15+
public conf(): ObjApi<Node> {
16+
return this.model.api.obj(['conf']) as ObjApi<Node>;
17+
}
18+
}

‎src/json-crdt-peritext-ui/plugins/toolbar/state/index.tsx‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {CommonSliceType, type LeafBlock, type Peritext} from '../../../../json-c
99
import {BehaviorSubject} from 'rxjs';
1010
import {compare, type ITimestampStruct} from '../../../../json-crdt-patch';
1111
import {SliceTypeCon} from '../../../../json-crdt-extensions/peritext/slice/constants';
12+
import {NewSliceConfig} from './format';
1213
import type {UiLifeCycles} from '../../../web/types';
1314
import type {BufferDetail, PeritextEventDetailMap} from '../../../events/types';
1415
import type {PeritextSurfaceState} from '../../../web';
@@ -21,6 +22,12 @@ export class ToolbarState implements UiLifeCycles {
2122
public lastEventTs: number = 0;
2223
public readonly showInlineToolbar = new ValueSyncStore<[show: boolean, time: number]>([false, 0]);
2324

25+
/**
26+
* New slice configuration. This is used for new slices which are not yet
27+
* applied to the text as they need to be configured first.
28+
*/
29+
public readonly newSliceConfig = new ValueSyncStore<NewSliceConfig | undefined>(void 0);
30+
2431
/**
2532
* The ID of the active (where the main cursor or focus is placed) leaf block.
2633
*/
@@ -102,6 +109,18 @@ export class ToolbarState implements UiLifeCycles {
102109
// return true;
103110
// }
104111

112+
public startSliceConfig(tag: SliceTypeCon | string | number): NewSliceConfig | undefined {
113+
const entry = this.txt.editor.getRegistry().get(tag);
114+
const newSliceConfig = this.newSliceConfig;
115+
if (!entry) {
116+
newSliceConfig.next(void 0);
117+
return;
118+
}
119+
const configState = new NewSliceConfig(entry);
120+
newSliceConfig.next(configState);
121+
return configState;
122+
}
123+
105124
// -------------------------------------------------------------------- Menus
106125

107126
public readonly getFormattingMenu = (): MenuItem => {
@@ -275,7 +294,7 @@ export class ToolbarState implements UiLifeCycles {
275294
// icon: () => <Iconista width={15} height={15} set="lucide" icon="link" />,
276295
icon: () => <Iconista width={15} height={15} set="radix" icon="link-2" />,
277296
onSelect: () => {
278-
et.format(CommonSliceType.a, 'many');
297+
this.startSliceConfig(CommonSliceType.a);
279298
},
280299
},
281300
// {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type {SliceRegistryEntry} from "../../../../json-crdt-extensions/peritext/registry/SliceRegistryEntry";
2+
import type {ObjApi} from "../../../../json-crdt/model";
3+
import type {ObjNode} from "../../../../json-crdt/nodes";
4+
5+
/**
6+
* Transient UI configuration state of a slice. Used to render to the user
7+
* slice configuration UI, such as popups, modals, etc.
8+
*/
9+
export interface SliceConfigState<Node extends ObjNode = ObjNode> {
10+
/** Slice definition in the registry. */
11+
def: SliceRegistryEntry;
12+
13+
/**
14+
* An object representing the actual configuration of this slice instance.
15+
* This object is either already stored in the document, or will be stored
16+
* when the user commits the changes.
17+
*/
18+
conf(): ObjApi<Node>;
19+
}

0 commit comments

Comments
 (0)