kopia lustrzana https://github.com/Tldraw/Tldraw
alex/auto-undo-redo: clean up page rename undo/redo
rodzic
0d11d3d253
commit
e341dbea06
|
@ -401,6 +401,7 @@ describe('history options', () => {
|
|||
manager.batch(
|
||||
() => {
|
||||
setA(1)
|
||||
// even though we set this to record, it will still be ignored
|
||||
manager.batch(() => setB(1), { history: 'record' })
|
||||
setA(2)
|
||||
},
|
||||
|
@ -408,9 +409,9 @@ describe('history options', () => {
|
|||
)
|
||||
expect(getState()).toMatchObject({ a: 2, b: 1 })
|
||||
|
||||
// changes to A were ignore, but changes to B were recorded:
|
||||
// changes were ignored:
|
||||
manager.undo()
|
||||
expect(getState()).toMatchObject({ a: 2, b: 0 })
|
||||
expect(getState()).toMatchObject({ a: 2, b: 1 })
|
||||
|
||||
manager.mark()
|
||||
manager.batch(
|
||||
|
@ -429,8 +430,5 @@ describe('history options', () => {
|
|||
// We can still redo because we preserved the redo stack:
|
||||
manager.redo()
|
||||
expect(getState()).toMatchObject({ a: 3, b: 2 })
|
||||
|
||||
manager.redo()
|
||||
expect(getState()).toMatchObject({ a: 3, b: 1 })
|
||||
})
|
||||
})
|
||||
|
|
|
@ -86,7 +86,11 @@ export class HistoryManager<R extends UnknownRecord> {
|
|||
_isInBatch = false
|
||||
batch = (fn: () => void, opts?: TLHistoryBatchOptions) => {
|
||||
const previousState = this.state
|
||||
this.state = opts?.history ? modeToState[opts.history] : this.state
|
||||
|
||||
// we move to the new state only if we haven't explicitly paused
|
||||
if (previousState !== HistoryRecorderState.Paused && opts?.history) {
|
||||
this.state = modeToState[opts.history]
|
||||
}
|
||||
|
||||
try {
|
||||
if (this._isInBatch) {
|
||||
|
|
|
@ -61,6 +61,9 @@ export function createRecordMigrationSequence(opts: {
|
|||
|
||||
// @public
|
||||
export function createRecordType<R extends UnknownRecord>(typeName: R['typeName'], config: {
|
||||
ephemeralKeys?: {
|
||||
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
|
||||
};
|
||||
scope: RecordScope;
|
||||
validator?: StoreValidator<R>;
|
||||
}): RecordType<R, keyof Omit<R, 'id' | 'typeName'>>;
|
||||
|
@ -193,6 +196,9 @@ export class RecordType<R extends UnknownRecord, RequiredProperties extends keyo
|
|||
constructor(
|
||||
typeName: R['typeName'], config: {
|
||||
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>;
|
||||
readonly ephemeralKeys?: {
|
||||
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
|
||||
};
|
||||
readonly scope?: RecordScope;
|
||||
readonly validator?: StoreValidator<R>;
|
||||
});
|
||||
|
@ -203,6 +209,12 @@ export class RecordType<R extends UnknownRecord, RequiredProperties extends keyo
|
|||
// (undocumented)
|
||||
readonly createDefaultProperties: () => Exclude<OmitMeta<R>, RequiredProperties>;
|
||||
createId(customUniquePart?: string): IdOf<R>;
|
||||
// (undocumented)
|
||||
readonly ephemeralKeys?: {
|
||||
readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean;
|
||||
};
|
||||
// (undocumented)
|
||||
readonly ephemeralKeySet: ReadonlySet<string>;
|
||||
isId(id?: string): id is IdOf<R>;
|
||||
isInstance: (record?: UnknownRecord) => record is R;
|
||||
parseId(id: IdOf<R>): string;
|
||||
|
@ -265,7 +277,10 @@ export class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {
|
|||
addHistoryInterceptor(fn: (entry: HistoryEntry<R>, source: ChangeSource) => void): () => void;
|
||||
allRecords: () => R[];
|
||||
// (undocumented)
|
||||
applyDiff(diff: RecordsDiff<R>, runCallbacks?: boolean): void;
|
||||
applyDiff(diff: RecordsDiff<R>, { runCallbacks, ignoreEphemeralKeys, }?: {
|
||||
ignoreEphemeralKeys?: boolean;
|
||||
runCallbacks?: boolean;
|
||||
}): void;
|
||||
// @internal (undocumented)
|
||||
atomic<T>(fn: () => T, runCallbacks?: boolean): T;
|
||||
clear: () => void;
|
||||
|
@ -342,6 +357,8 @@ export class StoreSchema<R extends UnknownRecord, P = unknown> {
|
|||
createIntegrityChecker(store: Store<R, P>): (() => void) | undefined;
|
||||
// (undocumented)
|
||||
getMigrationsSince(persistedSchema: SerializedSchema): Result<Migration[], string>;
|
||||
// @internal (undocumented)
|
||||
getType(typeName: string): RecordType<R, any>;
|
||||
// (undocumented)
|
||||
migratePersistedRecord(record: R, persistedSchema: SerializedSchema, direction?: 'down' | 'up'): MigrationResult<R>;
|
||||
// (undocumented)
|
||||
|
|
|
@ -802,7 +802,16 @@
|
|||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "{\n scope: "
|
||||
"text": "{\n ephemeralKeys?: {\n readonly [K in "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "Exclude",
|
||||
"canonicalReference": "!Exclude:type"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "<keyof R, 'id' | 'typeName'>]: boolean;\n };\n scope: "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
|
@ -851,8 +860,8 @@
|
|||
],
|
||||
"fileUrlPath": "packages/store/src/lib/RecordType.ts",
|
||||
"returnTypeTokenRange": {
|
||||
"startIndex": 11,
|
||||
"endIndex": 15
|
||||
"startIndex": 13,
|
||||
"endIndex": 17
|
||||
},
|
||||
"releaseTag": "Public",
|
||||
"overloadIndex": 1,
|
||||
|
@ -869,7 +878,7 @@
|
|||
"parameterName": "config",
|
||||
"parameterTypeTokenRange": {
|
||||
"startIndex": 5,
|
||||
"endIndex": 10
|
||||
"endIndex": 12
|
||||
},
|
||||
"isOptional": false
|
||||
}
|
||||
|
@ -2053,7 +2062,16 @@
|
|||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "<R>, RequiredProperties>;\n readonly scope?: "
|
||||
"text": "<R>, RequiredProperties>;\n readonly ephemeralKeys?: {\n readonly [K in "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "Exclude",
|
||||
"canonicalReference": "!Exclude:type"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "<keyof R, 'id' | 'typeName'>]: boolean;\n };\n readonly scope?: "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
|
@ -2094,7 +2112,7 @@
|
|||
"parameterName": "config",
|
||||
"parameterTypeTokenRange": {
|
||||
"startIndex": 3,
|
||||
"endIndex": 12
|
||||
"endIndex": 14
|
||||
},
|
||||
"isOptional": false
|
||||
}
|
||||
|
@ -2373,6 +2391,80 @@
|
|||
"isAbstract": false,
|
||||
"name": "createId"
|
||||
},
|
||||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/store!RecordType#ephemeralKeys:member",
|
||||
"docComment": "",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "readonly ephemeralKeys?: "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "{\n readonly [K in "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "Exclude",
|
||||
"canonicalReference": "!Exclude:type"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "<keyof R, 'id' | 'typeName'>]: boolean;\n }"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isReadonly": true,
|
||||
"isOptional": true,
|
||||
"releaseTag": "Public",
|
||||
"name": "ephemeralKeys",
|
||||
"propertyTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 4
|
||||
},
|
||||
"isStatic": false,
|
||||
"isProtected": false,
|
||||
"isAbstract": false
|
||||
},
|
||||
{
|
||||
"kind": "Property",
|
||||
"canonicalReference": "@tldraw/store!RecordType#ephemeralKeySet:member",
|
||||
"docComment": "",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "readonly ephemeralKeySet: "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "ReadonlySet",
|
||||
"canonicalReference": "!ReadonlySet:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "<string>"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isReadonly": true,
|
||||
"isOptional": false,
|
||||
"releaseTag": "Public",
|
||||
"name": "ephemeralKeySet",
|
||||
"propertyTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 3
|
||||
},
|
||||
"isStatic": false,
|
||||
"isProtected": false,
|
||||
"isAbstract": false
|
||||
},
|
||||
{
|
||||
"kind": "Method",
|
||||
"canonicalReference": "@tldraw/store!RecordType#isId:member(1)",
|
||||
|
@ -3408,11 +3500,11 @@
|
|||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ", runCallbacks?: "
|
||||
"text": ", { runCallbacks, ignoreEphemeralKeys, }?: "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "boolean"
|
||||
"text": "{\n ignoreEphemeralKeys?: boolean;\n runCallbacks?: boolean;\n }"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -3445,7 +3537,7 @@
|
|||
"isOptional": false
|
||||
},
|
||||
{
|
||||
"parameterName": "runCallbacks",
|
||||
"parameterName": "{ runCallbacks, ignoreEphemeralKeys, }",
|
||||
"parameterTypeTokenRange": {
|
||||
"startIndex": 4,
|
||||
"endIndex": 5
|
||||
|
|
|
@ -2165,6 +2165,8 @@ export interface TLUiInputProps {
|
|||
// (undocumented)
|
||||
onComplete?: (value: string) => void;
|
||||
// (undocumented)
|
||||
onFocus?: () => void;
|
||||
// (undocumented)
|
||||
onValueChange?: (value: string) => void;
|
||||
// (undocumented)
|
||||
placeholder?: string;
|
||||
|
|
|
@ -24472,6 +24472,33 @@
|
|||
"endIndex": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "PropertySignature",
|
||||
"canonicalReference": "tldraw!TLUiInputProps#onFocus:member",
|
||||
"docComment": "",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "onFocus?: "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "() => void"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isReadonly": false,
|
||||
"isOptional": true,
|
||||
"releaseTag": "Public",
|
||||
"name": "onFocus",
|
||||
"propertyTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "PropertySignature",
|
||||
"canonicalReference": "tldraw!TLUiInputProps#onValueChange:member",
|
||||
|
|
|
@ -15,18 +15,12 @@ export const PageItemInput = function PageItemInput({
|
|||
|
||||
const rInput = useRef<HTMLInputElement | null>(null)
|
||||
|
||||
const handleFocus = useCallback(() => {
|
||||
editor.mark('rename page')
|
||||
}, [editor])
|
||||
|
||||
const handleChange = useCallback(
|
||||
(value: string) => {
|
||||
editor.history.ignore(() => {
|
||||
editor.renamePage(id, value ? value : 'New Page')
|
||||
})
|
||||
},
|
||||
[editor, id]
|
||||
)
|
||||
|
||||
const handleComplete = useCallback(
|
||||
(value: string) => {
|
||||
editor.mark('rename page')
|
||||
editor.renamePage(id, value || 'New Page')
|
||||
},
|
||||
[editor, id]
|
||||
|
@ -38,8 +32,7 @@ export const PageItemInput = function PageItemInput({
|
|||
ref={(el) => (rInput.current = el)}
|
||||
defaultValue={name}
|
||||
onValueChange={handleChange}
|
||||
onComplete={handleComplete}
|
||||
onCancel={handleComplete}
|
||||
onFocus={handleFocus}
|
||||
shouldManuallyMaintainScrollPositionWhenFocused
|
||||
autofocus={isCurrentPage}
|
||||
autoselect
|
||||
|
|
|
@ -21,6 +21,7 @@ export interface TLUiInputProps {
|
|||
onValueChange?: (value: string) => void
|
||||
onCancel?: (value: string) => void
|
||||
onBlur?: (value: string) => void
|
||||
onFocus?: () => void
|
||||
className?: string
|
||||
/**
|
||||
* Usually on iOS when you focus an input, the browser will adjust the viewport to bring the input
|
||||
|
@ -49,6 +50,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
|
|||
onComplete,
|
||||
onValueChange,
|
||||
onCancel,
|
||||
onFocus,
|
||||
onBlur,
|
||||
shouldManuallyMaintainScrollPositionWhenFocused = false,
|
||||
children,
|
||||
|
@ -77,8 +79,9 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
|
|||
elm.select()
|
||||
}
|
||||
})
|
||||
onFocus?.()
|
||||
},
|
||||
[autoselect]
|
||||
[autoselect, onFocus]
|
||||
)
|
||||
|
||||
const handleChange = React.useCallback(
|
||||
|
|
Ładowanie…
Reference in New Issue