@portabletext/toolbar 4.0.23 → 4.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -5
- package/src/disable-listener.ts +0 -25
- package/src/index.ts +0 -11
- package/src/use-annotation-button.ts +0 -316
- package/src/use-annotation-popover.ts +0 -301
- package/src/use-block-object-button.ts +0 -189
- package/src/use-block-object-popover.ts +0 -285
- package/src/use-decorator-button.ts +0 -196
- package/src/use-decorator-keyboard-shortcut.ts +0 -96
- package/src/use-history-buttons.ts +0 -97
- package/src/use-inline-object-button.ts +0 -183
- package/src/use-inline-object-popover.ts +0 -285
- package/src/use-list-button.ts +0 -186
- package/src/use-mutually-exclusive-annotation.ts +0 -48
- package/src/use-mutually-exclusive-decorator.ts +0 -36
- package/src/use-style-keyboard-shortcuts.ts +0 -105
- package/src/use-style-selector.ts +0 -154
- package/src/use-toolbar-schema.ts +0 -166
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/toolbar",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.24",
|
|
4
4
|
"description": "Utilities for building a toolbar for the Portable Text Editor",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"portabletext",
|
|
@@ -29,14 +29,13 @@
|
|
|
29
29
|
"main": "./dist/index.js",
|
|
30
30
|
"types": "./dist/index.d.ts",
|
|
31
31
|
"files": [
|
|
32
|
-
"src",
|
|
33
32
|
"dist"
|
|
34
33
|
],
|
|
35
34
|
"dependencies": {
|
|
36
35
|
"@xstate/react": "^6.0.0",
|
|
37
36
|
"react-compiler-runtime": "^1.0.0",
|
|
38
37
|
"xstate": "^5.24.0",
|
|
39
|
-
"@portabletext/keyboard-shortcuts": "^2.1.
|
|
38
|
+
"@portabletext/keyboard-shortcuts": "^2.1.1"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@sanity/pkg-utils": "^10.1.1",
|
|
@@ -49,10 +48,10 @@
|
|
|
49
48
|
"react": "^19.2.1",
|
|
50
49
|
"typescript": "5.9.3",
|
|
51
50
|
"typescript-eslint": "^8.48.0",
|
|
52
|
-
"@portabletext/editor": "3.3.
|
|
51
|
+
"@portabletext/editor": "3.3.4"
|
|
53
52
|
},
|
|
54
53
|
"peerDependencies": {
|
|
55
|
-
"@portabletext/editor": "^3.3.
|
|
54
|
+
"@portabletext/editor": "^3.3.4",
|
|
56
55
|
"react": "^18.3 || ^19"
|
|
57
56
|
},
|
|
58
57
|
"engines": {
|
package/src/disable-listener.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type {Editor} from '@portabletext/editor'
|
|
2
|
-
import {fromCallback, type AnyEventObject} from 'xstate'
|
|
3
|
-
|
|
4
|
-
export type DisableListenerEvent = {type: 'enable'} | {type: 'disable'}
|
|
5
|
-
|
|
6
|
-
export const disableListener = fromCallback<
|
|
7
|
-
AnyEventObject,
|
|
8
|
-
{editor: Editor},
|
|
9
|
-
DisableListenerEvent
|
|
10
|
-
>(({input, sendBack}) => {
|
|
11
|
-
// Send back the initial state
|
|
12
|
-
if (input.editor.getSnapshot().context.readOnly) {
|
|
13
|
-
sendBack({type: 'disable'})
|
|
14
|
-
} else {
|
|
15
|
-
sendBack({type: 'enable'})
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return input.editor.on('*', () => {
|
|
19
|
-
if (input.editor.getSnapshot().context.readOnly) {
|
|
20
|
-
sendBack({type: 'disable'})
|
|
21
|
-
} else {
|
|
22
|
-
sendBack({type: 'enable'})
|
|
23
|
-
}
|
|
24
|
-
}).unsubscribe
|
|
25
|
-
})
|
package/src/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export * from './use-toolbar-schema'
|
|
2
|
-
export * from './use-annotation-button'
|
|
3
|
-
export * from './use-annotation-popover'
|
|
4
|
-
export * from './use-block-object-button'
|
|
5
|
-
export * from './use-block-object-popover'
|
|
6
|
-
export * from './use-decorator-button'
|
|
7
|
-
export * from './use-history-buttons'
|
|
8
|
-
export * from './use-inline-object-button'
|
|
9
|
-
export * from './use-inline-object-popover'
|
|
10
|
-
export * from './use-list-button'
|
|
11
|
-
export * from './use-style-selector'
|
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import {useEditor, type Editor} from '@portabletext/editor'
|
|
2
|
-
import {defineBehavior, effect, raise} from '@portabletext/editor/behaviors'
|
|
3
|
-
import * as selectors from '@portabletext/editor/selectors'
|
|
4
|
-
import {useActor} from '@xstate/react'
|
|
5
|
-
import {fromCallback, setup, type AnyEventObject} from 'xstate'
|
|
6
|
-
import {disableListener, type DisableListenerEvent} from './disable-listener'
|
|
7
|
-
import {useMutuallyExclusiveAnnotation} from './use-mutually-exclusive-annotation'
|
|
8
|
-
import type {ToolbarAnnotationSchemaType} from './use-toolbar-schema'
|
|
9
|
-
|
|
10
|
-
const activeListener = fromCallback<
|
|
11
|
-
AnyEventObject,
|
|
12
|
-
{editor: Editor; schemaType: ToolbarAnnotationSchemaType},
|
|
13
|
-
{type: 'set active'} | {type: 'set inactive'}
|
|
14
|
-
>(({input, sendBack}) => {
|
|
15
|
-
// Send back the initial state
|
|
16
|
-
if (
|
|
17
|
-
selectors.isActiveAnnotation(input.schemaType.name)(
|
|
18
|
-
input.editor.getSnapshot(),
|
|
19
|
-
)
|
|
20
|
-
) {
|
|
21
|
-
sendBack({type: 'set active'})
|
|
22
|
-
} else {
|
|
23
|
-
sendBack({type: 'set inactive'})
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return input.editor.on('*', () => {
|
|
27
|
-
const snapshot = input.editor.getSnapshot()
|
|
28
|
-
|
|
29
|
-
if (selectors.isActiveAnnotation(input.schemaType.name)(snapshot)) {
|
|
30
|
-
sendBack({type: 'set active'})
|
|
31
|
-
} else {
|
|
32
|
-
sendBack({type: 'set inactive'})
|
|
33
|
-
}
|
|
34
|
-
}).unsubscribe
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const keyboardShortcutRemove = fromCallback<
|
|
38
|
-
AnyEventObject,
|
|
39
|
-
{editor: Editor; schemaType: ToolbarAnnotationSchemaType}
|
|
40
|
-
>(({input}) => {
|
|
41
|
-
const shortcut = input.schemaType.shortcut
|
|
42
|
-
|
|
43
|
-
if (!shortcut) {
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return input.editor.registerBehavior({
|
|
48
|
-
behavior: defineBehavior({
|
|
49
|
-
on: 'keyboard.keydown',
|
|
50
|
-
guard: ({event}) => shortcut.guard(event.originEvent),
|
|
51
|
-
actions: [
|
|
52
|
-
() => [
|
|
53
|
-
raise({
|
|
54
|
-
type: 'annotation.remove',
|
|
55
|
-
annotation: {
|
|
56
|
-
name: input.schemaType.name,
|
|
57
|
-
},
|
|
58
|
-
}),
|
|
59
|
-
effect(() => {
|
|
60
|
-
input.editor.send({type: 'focus'})
|
|
61
|
-
}),
|
|
62
|
-
],
|
|
63
|
-
],
|
|
64
|
-
}),
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
const keyboardShortcutShowInsertDialog = fromCallback<
|
|
69
|
-
AnyEventObject,
|
|
70
|
-
{editor: Editor; schemaType: ToolbarAnnotationSchemaType},
|
|
71
|
-
{type: 'open dialog'}
|
|
72
|
-
>(({input, sendBack}) => {
|
|
73
|
-
const shortcut = input.schemaType.shortcut
|
|
74
|
-
|
|
75
|
-
if (!shortcut) {
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return input.editor.registerBehavior({
|
|
80
|
-
behavior: defineBehavior({
|
|
81
|
-
on: 'keyboard.keydown',
|
|
82
|
-
guard: ({event}) => shortcut.guard(event.originEvent),
|
|
83
|
-
actions: [
|
|
84
|
-
() => [
|
|
85
|
-
effect(() => {
|
|
86
|
-
sendBack({type: 'open dialog'})
|
|
87
|
-
}),
|
|
88
|
-
],
|
|
89
|
-
],
|
|
90
|
-
}),
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
const annotationButtonMachine = setup({
|
|
95
|
-
types: {
|
|
96
|
-
context: {} as {
|
|
97
|
-
editor: Editor
|
|
98
|
-
schemaType: ToolbarAnnotationSchemaType
|
|
99
|
-
},
|
|
100
|
-
input: {} as {
|
|
101
|
-
editor: Editor
|
|
102
|
-
schemaType: ToolbarAnnotationSchemaType
|
|
103
|
-
},
|
|
104
|
-
events: {} as
|
|
105
|
-
| AnnotationButtonEvent
|
|
106
|
-
| DisableListenerEvent
|
|
107
|
-
| {type: 'set active'}
|
|
108
|
-
| {type: 'set inactive'},
|
|
109
|
-
},
|
|
110
|
-
actions: {
|
|
111
|
-
'add annotation': ({context, event}) => {
|
|
112
|
-
if (event.type !== 'add') {
|
|
113
|
-
return
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
context.editor.send({
|
|
117
|
-
type: 'annotation.add',
|
|
118
|
-
annotation: {
|
|
119
|
-
name: context.schemaType.name,
|
|
120
|
-
value: event.annotation.value,
|
|
121
|
-
},
|
|
122
|
-
})
|
|
123
|
-
context.editor.send({type: 'focus'})
|
|
124
|
-
},
|
|
125
|
-
'remove annotation': ({context}) => {
|
|
126
|
-
context.editor.send({
|
|
127
|
-
type: 'annotation.remove',
|
|
128
|
-
annotation: {
|
|
129
|
-
name: context.schemaType.name,
|
|
130
|
-
},
|
|
131
|
-
})
|
|
132
|
-
context.editor.send({type: 'focus'})
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
actors: {
|
|
136
|
-
'active listener': activeListener,
|
|
137
|
-
'disable listener': disableListener,
|
|
138
|
-
'keyboard shortcut.remove': keyboardShortcutRemove,
|
|
139
|
-
'keyboard shortcut.show insert dialog': keyboardShortcutShowInsertDialog,
|
|
140
|
-
},
|
|
141
|
-
}).createMachine({
|
|
142
|
-
id: 'annotation button',
|
|
143
|
-
context: ({input}) => ({
|
|
144
|
-
editor: input.editor,
|
|
145
|
-
schemaType: input.schemaType,
|
|
146
|
-
}),
|
|
147
|
-
invoke: [
|
|
148
|
-
{
|
|
149
|
-
src: 'active listener',
|
|
150
|
-
input: ({context}) => ({
|
|
151
|
-
editor: context.editor,
|
|
152
|
-
schemaType: context.schemaType,
|
|
153
|
-
}),
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
src: 'disable listener',
|
|
157
|
-
input: ({context}) => ({
|
|
158
|
-
editor: context.editor,
|
|
159
|
-
schemaType: context.schemaType,
|
|
160
|
-
}),
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
initial: 'disabled',
|
|
164
|
-
states: {
|
|
165
|
-
disabled: {
|
|
166
|
-
initial: 'inactive',
|
|
167
|
-
states: {
|
|
168
|
-
inactive: {
|
|
169
|
-
on: {
|
|
170
|
-
'enable': {
|
|
171
|
-
target: '#annotation button.enabled.inactive',
|
|
172
|
-
},
|
|
173
|
-
'set active': {
|
|
174
|
-
target: 'active',
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
active: {
|
|
179
|
-
on: {
|
|
180
|
-
'enable': {
|
|
181
|
-
target: '#annotation button.enabled.active',
|
|
182
|
-
},
|
|
183
|
-
'set inactive': {
|
|
184
|
-
target: 'inactive',
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
enabled: {
|
|
191
|
-
initial: 'inactive',
|
|
192
|
-
states: {
|
|
193
|
-
inactive: {
|
|
194
|
-
initial: 'idle',
|
|
195
|
-
on: {
|
|
196
|
-
'disable': {
|
|
197
|
-
target: '#annotation button.disabled.inactive',
|
|
198
|
-
},
|
|
199
|
-
'set active': {
|
|
200
|
-
target: '#annotation button.enabled.active',
|
|
201
|
-
},
|
|
202
|
-
'add': {
|
|
203
|
-
actions: 'add annotation',
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
states: {
|
|
207
|
-
'idle': {
|
|
208
|
-
invoke: {
|
|
209
|
-
src: 'keyboard shortcut.show insert dialog',
|
|
210
|
-
input: ({context}) => ({
|
|
211
|
-
editor: context.editor,
|
|
212
|
-
schemaType: context.schemaType,
|
|
213
|
-
}),
|
|
214
|
-
},
|
|
215
|
-
on: {
|
|
216
|
-
'open dialog': {
|
|
217
|
-
target: 'showing dialog',
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
'showing dialog': {
|
|
222
|
-
on: {
|
|
223
|
-
'close dialog': {
|
|
224
|
-
target: 'idle',
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
active: {
|
|
231
|
-
invoke: {
|
|
232
|
-
src: 'keyboard shortcut.remove',
|
|
233
|
-
input: ({context}) => ({
|
|
234
|
-
editor: context.editor,
|
|
235
|
-
schemaType: context.schemaType,
|
|
236
|
-
}),
|
|
237
|
-
},
|
|
238
|
-
on: {
|
|
239
|
-
'set inactive': {
|
|
240
|
-
target: '#annotation button.enabled.inactive',
|
|
241
|
-
},
|
|
242
|
-
'disable': {
|
|
243
|
-
target: '#annotation button.disabled.active',
|
|
244
|
-
},
|
|
245
|
-
'remove': {
|
|
246
|
-
actions: 'remove annotation',
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
},
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
},
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* @beta
|
|
257
|
-
*/
|
|
258
|
-
export type AnnotationButtonEvent =
|
|
259
|
-
| {type: 'close dialog'}
|
|
260
|
-
| {type: 'open dialog'}
|
|
261
|
-
| {
|
|
262
|
-
type: 'add'
|
|
263
|
-
annotation: {
|
|
264
|
-
value: Record<string, unknown>
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
| {type: 'remove'}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* @beta
|
|
271
|
-
*/
|
|
272
|
-
export type AnnotationButton = {
|
|
273
|
-
snapshot: {
|
|
274
|
-
matches: (
|
|
275
|
-
state:
|
|
276
|
-
| 'disabled'
|
|
277
|
-
| 'enabled'
|
|
278
|
-
| {disabled: 'inactive'}
|
|
279
|
-
| {disabled: 'active'}
|
|
280
|
-
| {enabled: 'inactive'}
|
|
281
|
-
| {enabled: {inactive: 'idle'}}
|
|
282
|
-
| {enabled: {inactive: 'showing dialog'}}
|
|
283
|
-
| {enabled: 'active'},
|
|
284
|
-
) => boolean
|
|
285
|
-
}
|
|
286
|
-
send: (event: AnnotationButtonEvent) => void
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* @beta
|
|
291
|
-
* Manages the state, keyboard shortcut and available events for an annotation
|
|
292
|
-
* button.
|
|
293
|
-
*
|
|
294
|
-
* Note: This hook assumes that the button triggers a dialog for inputting
|
|
295
|
-
* the annotation value.
|
|
296
|
-
*/
|
|
297
|
-
export function useAnnotationButton(props: {
|
|
298
|
-
schemaType: ToolbarAnnotationSchemaType
|
|
299
|
-
}): AnnotationButton {
|
|
300
|
-
const editor = useEditor()
|
|
301
|
-
const [snapshot, send] = useActor(annotationButtonMachine, {
|
|
302
|
-
input: {
|
|
303
|
-
editor,
|
|
304
|
-
schemaType: props.schemaType,
|
|
305
|
-
},
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
useMutuallyExclusiveAnnotation(props)
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
snapshot: {
|
|
312
|
-
matches: (state) => snapshot.matches(state),
|
|
313
|
-
},
|
|
314
|
-
send,
|
|
315
|
-
}
|
|
316
|
-
}
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useEditor,
|
|
3
|
-
type AnnotationPath,
|
|
4
|
-
type AnnotationSchemaType,
|
|
5
|
-
type Editor,
|
|
6
|
-
type PortableTextObject,
|
|
7
|
-
} from '@portabletext/editor'
|
|
8
|
-
import * as selectors from '@portabletext/editor/selectors'
|
|
9
|
-
import {useActor} from '@xstate/react'
|
|
10
|
-
import * as React from 'react'
|
|
11
|
-
import type {RefObject} from 'react'
|
|
12
|
-
import {assign, fromCallback, setup, type AnyEventObject} from 'xstate'
|
|
13
|
-
import {disableListener, type DisableListenerEvent} from './disable-listener'
|
|
14
|
-
import type {ToolbarAnnotationSchemaType} from './use-toolbar-schema'
|
|
15
|
-
|
|
16
|
-
type ActiveContext = {
|
|
17
|
-
annotations: Array<{
|
|
18
|
-
value: PortableTextObject
|
|
19
|
-
schemaType: ToolbarAnnotationSchemaType
|
|
20
|
-
at: AnnotationPath
|
|
21
|
-
}>
|
|
22
|
-
elementRef: RefObject<Element | null>
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type ActiveListenerEvent =
|
|
26
|
-
| ({
|
|
27
|
-
type: 'set active'
|
|
28
|
-
} & ActiveContext)
|
|
29
|
-
| {
|
|
30
|
-
type: 'set inactive'
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const activeListener = fromCallback<
|
|
34
|
-
AnyEventObject,
|
|
35
|
-
{editor: Editor; schemaTypes: ReadonlyArray<ToolbarAnnotationSchemaType>},
|
|
36
|
-
ActiveListenerEvent
|
|
37
|
-
>(({input, sendBack}) => {
|
|
38
|
-
return input.editor.on('*', () => {
|
|
39
|
-
const snapshot = input.editor.getSnapshot()
|
|
40
|
-
const activeAnnotations = selectors.getActiveAnnotations(snapshot)
|
|
41
|
-
const focusBlock = selectors.getFocusBlock(snapshot)
|
|
42
|
-
|
|
43
|
-
if (activeAnnotations.length === 0 || !focusBlock) {
|
|
44
|
-
sendBack({type: 'set inactive'})
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const selectedChildren = input.editor.dom.getChildNodes(snapshot)
|
|
49
|
-
const firstSelectedChild = selectedChildren.at(0)
|
|
50
|
-
|
|
51
|
-
if (!firstSelectedChild || !(firstSelectedChild instanceof Element)) {
|
|
52
|
-
sendBack({type: 'set inactive'})
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const elementRef = React.createRef<Element>()
|
|
57
|
-
elementRef.current = firstSelectedChild
|
|
58
|
-
|
|
59
|
-
sendBack({
|
|
60
|
-
type: 'set active',
|
|
61
|
-
annotations: activeAnnotations.flatMap((annotation) => {
|
|
62
|
-
const schemaType = input.schemaTypes.find(
|
|
63
|
-
(schemaType) => schemaType.name === annotation._type,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
if (!schemaType) {
|
|
67
|
-
return []
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
value: annotation,
|
|
72
|
-
schemaType,
|
|
73
|
-
at: [
|
|
74
|
-
{_key: focusBlock.node._key},
|
|
75
|
-
'markDefs',
|
|
76
|
-
{_key: annotation._key},
|
|
77
|
-
],
|
|
78
|
-
}
|
|
79
|
-
}),
|
|
80
|
-
elementRef,
|
|
81
|
-
})
|
|
82
|
-
}).unsubscribe
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
const annotationPopoverMachine = setup({
|
|
86
|
-
types: {
|
|
87
|
-
context: {} as {
|
|
88
|
-
editor: Editor
|
|
89
|
-
schemaTypes: ReadonlyArray<ToolbarAnnotationSchemaType>
|
|
90
|
-
} & ActiveContext,
|
|
91
|
-
input: {} as {
|
|
92
|
-
editor: Editor
|
|
93
|
-
schemaTypes: ReadonlyArray<ToolbarAnnotationSchemaType>
|
|
94
|
-
},
|
|
95
|
-
events: {} as
|
|
96
|
-
| DisableListenerEvent
|
|
97
|
-
| ActiveListenerEvent
|
|
98
|
-
| AnnotationPopoverEvent,
|
|
99
|
-
},
|
|
100
|
-
actions: {
|
|
101
|
-
reset: assign({
|
|
102
|
-
annotations: [],
|
|
103
|
-
elementRef: React.createRef<Element>(),
|
|
104
|
-
}),
|
|
105
|
-
remove: ({context, event}) => {
|
|
106
|
-
if (event.type !== 'remove') {
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
context.editor.send({
|
|
111
|
-
type: 'annotation.remove',
|
|
112
|
-
annotation: {
|
|
113
|
-
name: event.schemaType.name,
|
|
114
|
-
},
|
|
115
|
-
})
|
|
116
|
-
context.editor.send({type: 'focus'})
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
actors: {
|
|
120
|
-
'disable listener': disableListener,
|
|
121
|
-
'active listener': activeListener,
|
|
122
|
-
},
|
|
123
|
-
}).createMachine({
|
|
124
|
-
id: 'annotation popover',
|
|
125
|
-
context: ({input}) => ({
|
|
126
|
-
editor: input.editor,
|
|
127
|
-
schemaTypes: input.schemaTypes,
|
|
128
|
-
annotations: [],
|
|
129
|
-
elementRef: React.createRef<Element>(),
|
|
130
|
-
}),
|
|
131
|
-
invoke: [
|
|
132
|
-
{src: 'disable listener', input: ({context}) => ({editor: context.editor})},
|
|
133
|
-
],
|
|
134
|
-
initial: 'disabled',
|
|
135
|
-
states: {
|
|
136
|
-
disabled: {
|
|
137
|
-
initial: 'inactive',
|
|
138
|
-
states: {
|
|
139
|
-
inactive: {
|
|
140
|
-
entry: ['reset'],
|
|
141
|
-
on: {
|
|
142
|
-
'set active': {
|
|
143
|
-
actions: assign({
|
|
144
|
-
annotations: ({event}) => event.annotations,
|
|
145
|
-
elementRef: ({event}) => event.elementRef,
|
|
146
|
-
}),
|
|
147
|
-
target: 'active',
|
|
148
|
-
},
|
|
149
|
-
'enable': {
|
|
150
|
-
target: '#annotation popover.enabled.inactive',
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
active: {
|
|
155
|
-
on: {
|
|
156
|
-
'set inactive': {
|
|
157
|
-
target: 'inactive',
|
|
158
|
-
},
|
|
159
|
-
'enable': {
|
|
160
|
-
target: '#annotation popover.enabled.active',
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
enabled: {
|
|
167
|
-
invoke: [
|
|
168
|
-
{
|
|
169
|
-
src: 'active listener',
|
|
170
|
-
input: ({context}) => ({
|
|
171
|
-
editor: context.editor,
|
|
172
|
-
schemaTypes: context.schemaTypes,
|
|
173
|
-
}),
|
|
174
|
-
},
|
|
175
|
-
],
|
|
176
|
-
initial: 'inactive',
|
|
177
|
-
states: {
|
|
178
|
-
inactive: {
|
|
179
|
-
entry: ['reset'],
|
|
180
|
-
on: {
|
|
181
|
-
'set active': {
|
|
182
|
-
target: 'active',
|
|
183
|
-
actions: assign({
|
|
184
|
-
annotations: ({event}) => event.annotations,
|
|
185
|
-
elementRef: ({event}) => event.elementRef,
|
|
186
|
-
}),
|
|
187
|
-
},
|
|
188
|
-
'disable': {
|
|
189
|
-
target: '#annotation popover.disabled.inactive',
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
active: {
|
|
194
|
-
on: {
|
|
195
|
-
'set inactive': {
|
|
196
|
-
target: 'inactive',
|
|
197
|
-
},
|
|
198
|
-
'disable': {
|
|
199
|
-
target: '#annotation popover.disabled.active',
|
|
200
|
-
},
|
|
201
|
-
'set active': {
|
|
202
|
-
actions: assign({
|
|
203
|
-
annotations: ({event}) => event.annotations,
|
|
204
|
-
elementRef: ({event}) => event.elementRef,
|
|
205
|
-
}),
|
|
206
|
-
},
|
|
207
|
-
'edit': {
|
|
208
|
-
actions: ({context, event}) => {
|
|
209
|
-
context.editor.send({
|
|
210
|
-
type: 'annotation.set',
|
|
211
|
-
at: event.at,
|
|
212
|
-
props: event.props,
|
|
213
|
-
})
|
|
214
|
-
context.editor.send({type: 'focus'})
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
'remove': {
|
|
218
|
-
actions: ({context, event}) => {
|
|
219
|
-
context.editor.send({
|
|
220
|
-
type: 'annotation.remove',
|
|
221
|
-
annotation: {
|
|
222
|
-
name: event.schemaType.name,
|
|
223
|
-
},
|
|
224
|
-
})
|
|
225
|
-
context.editor.send({type: 'focus'})
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
'close': {
|
|
229
|
-
actions: ({context}) => {
|
|
230
|
-
context.editor.send({type: 'focus'})
|
|
231
|
-
},
|
|
232
|
-
target: 'inactive',
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
},
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* @beta
|
|
243
|
-
*/
|
|
244
|
-
export type AnnotationPopoverEvent =
|
|
245
|
-
| {
|
|
246
|
-
type: 'remove'
|
|
247
|
-
schemaType: AnnotationSchemaType
|
|
248
|
-
}
|
|
249
|
-
| {
|
|
250
|
-
type: 'edit'
|
|
251
|
-
at: AnnotationPath
|
|
252
|
-
props: {[key: string]: unknown}
|
|
253
|
-
}
|
|
254
|
-
| {
|
|
255
|
-
type: 'close'
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* @beta
|
|
260
|
-
*/
|
|
261
|
-
export type AnnotationPopover = {
|
|
262
|
-
snapshot: {
|
|
263
|
-
context: ActiveContext
|
|
264
|
-
matches: (
|
|
265
|
-
state:
|
|
266
|
-
| 'disabled'
|
|
267
|
-
| 'enabled'
|
|
268
|
-
| {
|
|
269
|
-
enabled: 'inactive' | 'active'
|
|
270
|
-
},
|
|
271
|
-
) => boolean
|
|
272
|
-
}
|
|
273
|
-
send: (event: AnnotationPopoverEvent) => void
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* @beta
|
|
278
|
-
* Manages the state and available events for an annotation popover.
|
|
279
|
-
*/
|
|
280
|
-
export function useAnnotationPopover(props: {
|
|
281
|
-
schemaTypes: ReadonlyArray<ToolbarAnnotationSchemaType>
|
|
282
|
-
}): AnnotationPopover {
|
|
283
|
-
const editor = useEditor()
|
|
284
|
-
const [actorSnapshot, send] = useActor(annotationPopoverMachine, {
|
|
285
|
-
input: {
|
|
286
|
-
editor,
|
|
287
|
-
schemaTypes: props.schemaTypes,
|
|
288
|
-
},
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
return {
|
|
292
|
-
snapshot: {
|
|
293
|
-
context: {
|
|
294
|
-
annotations: actorSnapshot.context.annotations,
|
|
295
|
-
elementRef: actorSnapshot.context.elementRef,
|
|
296
|
-
},
|
|
297
|
-
matches: (state) => actorSnapshot.matches(state),
|
|
298
|
-
},
|
|
299
|
-
send,
|
|
300
|
-
}
|
|
301
|
-
}
|