@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
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import {useEditor, type Editor} from '@portabletext/editor'
|
|
2
|
-
import {
|
|
3
|
-
defineBehavior,
|
|
4
|
-
effect,
|
|
5
|
-
type InsertPlacement,
|
|
6
|
-
} from '@portabletext/editor/behaviors'
|
|
7
|
-
import {useActor} from '@xstate/react'
|
|
8
|
-
import {fromCallback, setup, type AnyEventObject} from 'xstate'
|
|
9
|
-
import {disableListener, type DisableListenerEvent} from './disable-listener'
|
|
10
|
-
import type {ToolbarBlockObjectSchemaType} from './use-toolbar-schema'
|
|
11
|
-
|
|
12
|
-
const keyboardShortcutListener = fromCallback<
|
|
13
|
-
AnyEventObject,
|
|
14
|
-
{editor: Editor; schemaType: ToolbarBlockObjectSchemaType},
|
|
15
|
-
BlockObjectButtonEvent
|
|
16
|
-
>(({input, sendBack}) => {
|
|
17
|
-
const shortcut = input.schemaType.shortcut
|
|
18
|
-
|
|
19
|
-
if (!shortcut) {
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return input.editor.registerBehavior({
|
|
24
|
-
behavior: defineBehavior({
|
|
25
|
-
on: 'keyboard.keydown',
|
|
26
|
-
guard: ({event}) => shortcut.guard(event.originEvent),
|
|
27
|
-
actions: [
|
|
28
|
-
() => [
|
|
29
|
-
effect(() => {
|
|
30
|
-
sendBack({type: 'open dialog'})
|
|
31
|
-
}),
|
|
32
|
-
],
|
|
33
|
-
],
|
|
34
|
-
}),
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
const blockObjectButtonMachine = setup({
|
|
39
|
-
types: {
|
|
40
|
-
context: {} as {
|
|
41
|
-
editor: Editor
|
|
42
|
-
schemaType: ToolbarBlockObjectSchemaType
|
|
43
|
-
},
|
|
44
|
-
input: {} as {
|
|
45
|
-
editor: Editor
|
|
46
|
-
schemaType: ToolbarBlockObjectSchemaType
|
|
47
|
-
},
|
|
48
|
-
events: {} as DisableListenerEvent | BlockObjectButtonEvent,
|
|
49
|
-
},
|
|
50
|
-
actions: {
|
|
51
|
-
insert: ({context, event}) => {
|
|
52
|
-
if (event.type !== 'insert') {
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
context.editor.send({
|
|
57
|
-
type: 'insert.block object',
|
|
58
|
-
blockObject: {
|
|
59
|
-
name: context.schemaType.name,
|
|
60
|
-
value: event.value,
|
|
61
|
-
},
|
|
62
|
-
placement: event.placement ?? 'auto',
|
|
63
|
-
})
|
|
64
|
-
context.editor.send({type: 'focus'})
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
actors: {
|
|
68
|
-
'disable listener': disableListener,
|
|
69
|
-
'keyboard shortcut listener': keyboardShortcutListener,
|
|
70
|
-
},
|
|
71
|
-
}).createMachine({
|
|
72
|
-
id: 'block object button',
|
|
73
|
-
context: ({input}) => ({
|
|
74
|
-
editor: input.editor,
|
|
75
|
-
schemaType: input.schemaType,
|
|
76
|
-
}),
|
|
77
|
-
invoke: [
|
|
78
|
-
{
|
|
79
|
-
src: 'disable listener',
|
|
80
|
-
input: ({context}) => ({editor: context.editor}),
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
initial: 'disabled',
|
|
84
|
-
states: {
|
|
85
|
-
disabled: {
|
|
86
|
-
on: {
|
|
87
|
-
enable: {
|
|
88
|
-
target: 'enabled',
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
enabled: {
|
|
93
|
-
on: {
|
|
94
|
-
disable: {
|
|
95
|
-
target: 'disabled',
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
initial: 'idle',
|
|
99
|
-
states: {
|
|
100
|
-
'idle': {
|
|
101
|
-
invoke: [
|
|
102
|
-
{
|
|
103
|
-
src: 'keyboard shortcut listener',
|
|
104
|
-
input: ({context}) => ({
|
|
105
|
-
editor: context.editor,
|
|
106
|
-
schemaType: context.schemaType,
|
|
107
|
-
}),
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
|
-
on: {
|
|
111
|
-
'open dialog': {
|
|
112
|
-
target: 'showing dialog',
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
'showing dialog': {
|
|
117
|
-
on: {
|
|
118
|
-
'close dialog': {
|
|
119
|
-
target: 'idle',
|
|
120
|
-
},
|
|
121
|
-
'insert': {
|
|
122
|
-
actions: ['insert'],
|
|
123
|
-
target: 'idle',
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* @beta
|
|
134
|
-
*/
|
|
135
|
-
export type BlockObjectButtonEvent =
|
|
136
|
-
| {
|
|
137
|
-
type: 'close dialog'
|
|
138
|
-
}
|
|
139
|
-
| {
|
|
140
|
-
type: 'open dialog'
|
|
141
|
-
}
|
|
142
|
-
| {
|
|
143
|
-
type: 'insert'
|
|
144
|
-
value: {[key: string]: unknown}
|
|
145
|
-
placement: InsertPlacement | undefined
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* @beta
|
|
150
|
-
*/
|
|
151
|
-
export type BlockObjectButton = {
|
|
152
|
-
snapshot: {
|
|
153
|
-
matches: (
|
|
154
|
-
state:
|
|
155
|
-
| 'disabled'
|
|
156
|
-
| 'enabled'
|
|
157
|
-
| {enabled: 'idle'}
|
|
158
|
-
| {enabled: 'showing dialog'},
|
|
159
|
-
) => boolean
|
|
160
|
-
}
|
|
161
|
-
send: (event: BlockObjectButtonEvent) => void
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* @beta
|
|
166
|
-
* Manages the state, keyboard shortcut and available events for a block
|
|
167
|
-
* object button.
|
|
168
|
-
*
|
|
169
|
-
* Note: This hook assumes that the button triggers a dialog for inputting
|
|
170
|
-
* the block object value.
|
|
171
|
-
*/
|
|
172
|
-
export function useBlockObjectButton(props: {
|
|
173
|
-
schemaType: ToolbarBlockObjectSchemaType
|
|
174
|
-
}): BlockObjectButton {
|
|
175
|
-
const editor = useEditor()
|
|
176
|
-
const [actorSnapshot, send] = useActor(blockObjectButtonMachine, {
|
|
177
|
-
input: {
|
|
178
|
-
editor,
|
|
179
|
-
schemaType: props.schemaType,
|
|
180
|
-
},
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
snapshot: {
|
|
185
|
-
matches: (state) => actorSnapshot.matches(state),
|
|
186
|
-
},
|
|
187
|
-
send,
|
|
188
|
-
}
|
|
189
|
-
}
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useEditor,
|
|
3
|
-
type BlockPath,
|
|
4
|
-
type Editor,
|
|
5
|
-
type PortableTextObject,
|
|
6
|
-
} from '@portabletext/editor'
|
|
7
|
-
import * as selectors from '@portabletext/editor/selectors'
|
|
8
|
-
import {useActor} from '@xstate/react'
|
|
9
|
-
import * as React from 'react'
|
|
10
|
-
import type {RefObject} from 'react'
|
|
11
|
-
import {assign, fromCallback, setup, type AnyEventObject} from 'xstate'
|
|
12
|
-
import {disableListener, type DisableListenerEvent} from './disable-listener'
|
|
13
|
-
import type {ToolbarBlockObjectSchemaType} from './use-toolbar-schema'
|
|
14
|
-
|
|
15
|
-
type ActiveContext = {
|
|
16
|
-
blockObjects: Array<{
|
|
17
|
-
value: PortableTextObject
|
|
18
|
-
schemaType: ToolbarBlockObjectSchemaType
|
|
19
|
-
at: BlockPath
|
|
20
|
-
}>
|
|
21
|
-
elementRef: RefObject<Element | null>
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
type ActiveListenerEvent =
|
|
25
|
-
| ({
|
|
26
|
-
type: 'set active'
|
|
27
|
-
} & ActiveContext)
|
|
28
|
-
| {
|
|
29
|
-
type: 'set inactive'
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const activeListener = fromCallback<
|
|
33
|
-
AnyEventObject,
|
|
34
|
-
{editor: Editor; schemaTypes: ReadonlyArray<ToolbarBlockObjectSchemaType>},
|
|
35
|
-
ActiveListenerEvent
|
|
36
|
-
>(({input, sendBack}) => {
|
|
37
|
-
return input.editor.on('selection', () => {
|
|
38
|
-
const snapshot = input.editor.getSnapshot()
|
|
39
|
-
|
|
40
|
-
if (!selectors.isSelectionCollapsed(snapshot)) {
|
|
41
|
-
sendBack({type: 'set inactive'})
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const focusBlockObject = selectors.getFocusBlockObject(snapshot)
|
|
46
|
-
|
|
47
|
-
if (!focusBlockObject) {
|
|
48
|
-
sendBack({type: 'set inactive'})
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const schemaType = input.schemaTypes.find(
|
|
53
|
-
(schemaType) => schemaType.name === focusBlockObject.node._type,
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
if (!schemaType) {
|
|
57
|
-
sendBack({type: 'set inactive'})
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const selectedNodes = input.editor.dom.getBlockNodes(snapshot)
|
|
62
|
-
const firstSelectedNode = selectedNodes.at(0)
|
|
63
|
-
|
|
64
|
-
if (!firstSelectedNode || !(firstSelectedNode instanceof Element)) {
|
|
65
|
-
sendBack({type: 'set inactive'})
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const elementRef = React.createRef<Element>()
|
|
70
|
-
elementRef.current = firstSelectedNode
|
|
71
|
-
|
|
72
|
-
sendBack({
|
|
73
|
-
type: 'set active',
|
|
74
|
-
blockObjects: [
|
|
75
|
-
{
|
|
76
|
-
value: focusBlockObject.node,
|
|
77
|
-
schemaType,
|
|
78
|
-
at: focusBlockObject.path,
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
elementRef,
|
|
82
|
-
})
|
|
83
|
-
}).unsubscribe
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const blockObjectPopoverMachine = setup({
|
|
87
|
-
types: {
|
|
88
|
-
context: {} as {
|
|
89
|
-
editor: Editor
|
|
90
|
-
schemaTypes: ReadonlyArray<ToolbarBlockObjectSchemaType>
|
|
91
|
-
} & ActiveContext,
|
|
92
|
-
input: {} as {
|
|
93
|
-
editor: Editor
|
|
94
|
-
schemaTypes: ReadonlyArray<ToolbarBlockObjectSchemaType>
|
|
95
|
-
},
|
|
96
|
-
events: {} as
|
|
97
|
-
| DisableListenerEvent
|
|
98
|
-
| ActiveListenerEvent
|
|
99
|
-
| BlockObjectPopoverEvent,
|
|
100
|
-
},
|
|
101
|
-
actions: {
|
|
102
|
-
reset: assign({
|
|
103
|
-
blockObjects: [],
|
|
104
|
-
elementRef: React.createRef<Element>(),
|
|
105
|
-
}),
|
|
106
|
-
},
|
|
107
|
-
actors: {
|
|
108
|
-
'disable listener': disableListener,
|
|
109
|
-
'active listener': activeListener,
|
|
110
|
-
},
|
|
111
|
-
}).createMachine({
|
|
112
|
-
id: 'block object popover',
|
|
113
|
-
context: ({input}) => ({
|
|
114
|
-
editor: input.editor,
|
|
115
|
-
schemaTypes: input.schemaTypes,
|
|
116
|
-
blockObjects: [],
|
|
117
|
-
elementRef: React.createRef<Element>(),
|
|
118
|
-
}),
|
|
119
|
-
invoke: [
|
|
120
|
-
{src: 'disable listener', input: ({context}) => ({editor: context.editor})},
|
|
121
|
-
{
|
|
122
|
-
src: 'active listener',
|
|
123
|
-
input: ({context}) => ({
|
|
124
|
-
editor: context.editor,
|
|
125
|
-
schemaTypes: context.schemaTypes,
|
|
126
|
-
}),
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
initial: 'disabled',
|
|
130
|
-
states: {
|
|
131
|
-
disabled: {
|
|
132
|
-
initial: 'inactive',
|
|
133
|
-
states: {
|
|
134
|
-
inactive: {
|
|
135
|
-
entry: ['reset'],
|
|
136
|
-
on: {
|
|
137
|
-
'set active': {
|
|
138
|
-
actions: assign({
|
|
139
|
-
blockObjects: ({event}) => event.blockObjects,
|
|
140
|
-
elementRef: ({event}) => event.elementRef,
|
|
141
|
-
}),
|
|
142
|
-
target: 'active',
|
|
143
|
-
},
|
|
144
|
-
'enable': {
|
|
145
|
-
target: '#block object popover.enabled.inactive',
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
active: {
|
|
150
|
-
on: {
|
|
151
|
-
'set inactive': {
|
|
152
|
-
target: 'inactive',
|
|
153
|
-
},
|
|
154
|
-
'enable': {
|
|
155
|
-
target: '#block object popover.enabled.active',
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
enabled: {
|
|
162
|
-
initial: 'inactive',
|
|
163
|
-
states: {
|
|
164
|
-
inactive: {
|
|
165
|
-
entry: ['reset'],
|
|
166
|
-
on: {
|
|
167
|
-
'set active': {
|
|
168
|
-
target: 'active',
|
|
169
|
-
actions: assign({
|
|
170
|
-
blockObjects: ({event}) => event.blockObjects,
|
|
171
|
-
elementRef: ({event}) => event.elementRef,
|
|
172
|
-
}),
|
|
173
|
-
},
|
|
174
|
-
'disable': {
|
|
175
|
-
target: '#block object popover.disabled.inactive',
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
active: {
|
|
180
|
-
on: {
|
|
181
|
-
'set inactive': {
|
|
182
|
-
target: 'inactive',
|
|
183
|
-
},
|
|
184
|
-
'disable': {
|
|
185
|
-
target: '#block object popover.disabled.active',
|
|
186
|
-
},
|
|
187
|
-
'set active': {
|
|
188
|
-
actions: assign({
|
|
189
|
-
blockObjects: ({event}) => event.blockObjects,
|
|
190
|
-
elementRef: ({event}) => event.elementRef,
|
|
191
|
-
}),
|
|
192
|
-
},
|
|
193
|
-
'edit': {
|
|
194
|
-
actions: ({context, event}) => {
|
|
195
|
-
context.editor.send({
|
|
196
|
-
type: 'block.set',
|
|
197
|
-
at: event.at,
|
|
198
|
-
props: event.props,
|
|
199
|
-
})
|
|
200
|
-
context.editor.send({type: 'focus'})
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
'remove': {
|
|
204
|
-
actions: ({context, event}) => {
|
|
205
|
-
context.editor.send({
|
|
206
|
-
type: 'delete.block',
|
|
207
|
-
at: event.at,
|
|
208
|
-
})
|
|
209
|
-
context.editor.send({type: 'focus'})
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
'close': {
|
|
213
|
-
actions: ({context}) => {
|
|
214
|
-
context.editor.send({type: 'focus'})
|
|
215
|
-
},
|
|
216
|
-
target: 'inactive',
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* @beta
|
|
227
|
-
*/
|
|
228
|
-
export type BlockObjectPopoverEvent =
|
|
229
|
-
| {
|
|
230
|
-
type: 'remove'
|
|
231
|
-
at: BlockPath
|
|
232
|
-
}
|
|
233
|
-
| {
|
|
234
|
-
type: 'edit'
|
|
235
|
-
at: BlockPath
|
|
236
|
-
props: {[key: string]: unknown}
|
|
237
|
-
}
|
|
238
|
-
| {
|
|
239
|
-
type: 'close'
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* @beta
|
|
244
|
-
*/
|
|
245
|
-
export type BlockObjectPopover = {
|
|
246
|
-
snapshot: {
|
|
247
|
-
context: ActiveContext
|
|
248
|
-
matches: (
|
|
249
|
-
state:
|
|
250
|
-
| 'disabled'
|
|
251
|
-
| 'enabled'
|
|
252
|
-
| {
|
|
253
|
-
enabled: 'inactive' | 'active'
|
|
254
|
-
},
|
|
255
|
-
) => boolean
|
|
256
|
-
}
|
|
257
|
-
send: (event: BlockObjectPopoverEvent) => void
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* @beta
|
|
262
|
-
* Manages the state and available events for a block object popover.
|
|
263
|
-
*/
|
|
264
|
-
export function useBlockObjectPopover(props: {
|
|
265
|
-
schemaTypes: ReadonlyArray<ToolbarBlockObjectSchemaType>
|
|
266
|
-
}): BlockObjectPopover {
|
|
267
|
-
const editor = useEditor()
|
|
268
|
-
const [actorSnapshot, send] = useActor(blockObjectPopoverMachine, {
|
|
269
|
-
input: {
|
|
270
|
-
editor,
|
|
271
|
-
schemaTypes: props.schemaTypes,
|
|
272
|
-
},
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
return {
|
|
276
|
-
snapshot: {
|
|
277
|
-
context: {
|
|
278
|
-
blockObjects: actorSnapshot.context.blockObjects,
|
|
279
|
-
elementRef: actorSnapshot.context.elementRef,
|
|
280
|
-
},
|
|
281
|
-
matches: (state) => actorSnapshot.matches(state),
|
|
282
|
-
},
|
|
283
|
-
send,
|
|
284
|
-
}
|
|
285
|
-
}
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useEditor,
|
|
3
|
-
type DecoratorSchemaType,
|
|
4
|
-
type Editor,
|
|
5
|
-
} from '@portabletext/editor'
|
|
6
|
-
import * as selectors from '@portabletext/editor/selectors'
|
|
7
|
-
import {useActor} from '@xstate/react'
|
|
8
|
-
import {fromCallback, setup, type AnyEventObject} from 'xstate'
|
|
9
|
-
import {disableListener, type DisableListenerEvent} from './disable-listener'
|
|
10
|
-
import {useDecoratorKeyboardShortcut} from './use-decorator-keyboard-shortcut'
|
|
11
|
-
import {useMutuallyExclusiveDecorator} from './use-mutually-exclusive-decorator'
|
|
12
|
-
import type {ToolbarDecoratorSchemaType} from './use-toolbar-schema'
|
|
13
|
-
|
|
14
|
-
const activeListener = fromCallback<
|
|
15
|
-
AnyEventObject,
|
|
16
|
-
{editor: Editor; schemaType: DecoratorSchemaType},
|
|
17
|
-
{type: 'set active'} | {type: 'set inactive'}
|
|
18
|
-
>(({input, sendBack}) => {
|
|
19
|
-
// Send back the initial state
|
|
20
|
-
if (
|
|
21
|
-
selectors.isActiveDecorator(input.schemaType.name)(
|
|
22
|
-
input.editor.getSnapshot(),
|
|
23
|
-
)
|
|
24
|
-
) {
|
|
25
|
-
sendBack({type: 'set active'})
|
|
26
|
-
} else {
|
|
27
|
-
sendBack({type: 'set inactive'})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return input.editor.on('*', () => {
|
|
31
|
-
const snapshot = input.editor.getSnapshot()
|
|
32
|
-
|
|
33
|
-
if (selectors.isActiveDecorator(input.schemaType.name)(snapshot)) {
|
|
34
|
-
sendBack({type: 'set active'})
|
|
35
|
-
} else {
|
|
36
|
-
sendBack({type: 'set inactive'})
|
|
37
|
-
}
|
|
38
|
-
}).unsubscribe
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const decoratorButtonMachine = setup({
|
|
42
|
-
types: {
|
|
43
|
-
context: {} as {
|
|
44
|
-
editor: Editor
|
|
45
|
-
schemaType: DecoratorSchemaType
|
|
46
|
-
},
|
|
47
|
-
input: {} as {
|
|
48
|
-
editor: Editor
|
|
49
|
-
schemaType: DecoratorSchemaType
|
|
50
|
-
},
|
|
51
|
-
events: {} as DisableListenerEvent | DecoratorButtonEvent,
|
|
52
|
-
},
|
|
53
|
-
actions: {
|
|
54
|
-
toggle: ({context, event}) => {
|
|
55
|
-
if (event.type !== 'toggle') {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
context.editor.send({
|
|
60
|
-
type: 'decorator.toggle',
|
|
61
|
-
decorator: context.schemaType.name,
|
|
62
|
-
})
|
|
63
|
-
context.editor.send({type: 'focus'})
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
actors: {
|
|
67
|
-
'disable listener': disableListener,
|
|
68
|
-
'active listener': activeListener,
|
|
69
|
-
},
|
|
70
|
-
}).createMachine({
|
|
71
|
-
id: 'decorator button',
|
|
72
|
-
context: ({input}) => ({
|
|
73
|
-
editor: input.editor,
|
|
74
|
-
schemaType: input.schemaType,
|
|
75
|
-
}),
|
|
76
|
-
invoke: [
|
|
77
|
-
{src: 'disable listener', input: ({context}) => ({editor: context.editor})},
|
|
78
|
-
{
|
|
79
|
-
src: 'active listener',
|
|
80
|
-
input: ({context}) => ({
|
|
81
|
-
editor: context.editor,
|
|
82
|
-
schemaType: context.schemaType,
|
|
83
|
-
}),
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
initial: 'disabled',
|
|
87
|
-
states: {
|
|
88
|
-
disabled: {
|
|
89
|
-
initial: 'inactive',
|
|
90
|
-
states: {
|
|
91
|
-
inactive: {
|
|
92
|
-
on: {
|
|
93
|
-
'enable': {
|
|
94
|
-
target: '#decorator button.enabled.inactive',
|
|
95
|
-
},
|
|
96
|
-
'set active': {
|
|
97
|
-
target: 'active',
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
active: {
|
|
102
|
-
on: {
|
|
103
|
-
'enable': {
|
|
104
|
-
target: '#decorator button.enabled.active',
|
|
105
|
-
},
|
|
106
|
-
'set inactive': {
|
|
107
|
-
target: 'inactive',
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
enabled: {
|
|
114
|
-
on: {
|
|
115
|
-
toggle: {
|
|
116
|
-
actions: ['toggle'],
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
initial: 'inactive',
|
|
120
|
-
states: {
|
|
121
|
-
inactive: {
|
|
122
|
-
on: {
|
|
123
|
-
'disable': {
|
|
124
|
-
target: '#decorator button.disabled.inactive',
|
|
125
|
-
},
|
|
126
|
-
'set active': {
|
|
127
|
-
target: 'active',
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
active: {
|
|
132
|
-
on: {
|
|
133
|
-
'disable': {
|
|
134
|
-
target: '#decorator button.disabled.active',
|
|
135
|
-
},
|
|
136
|
-
'set inactive': {
|
|
137
|
-
target: 'inactive',
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* @beta
|
|
148
|
-
*/
|
|
149
|
-
export type DecoratorButtonEvent = {
|
|
150
|
-
type: 'toggle'
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* @beta
|
|
155
|
-
*/
|
|
156
|
-
export type DecoratorButton = {
|
|
157
|
-
snapshot: {
|
|
158
|
-
matches: (
|
|
159
|
-
state:
|
|
160
|
-
| 'disabled'
|
|
161
|
-
| 'enabled'
|
|
162
|
-
| {disabled: 'inactive'}
|
|
163
|
-
| {disabled: 'active'}
|
|
164
|
-
| {enabled: 'inactive'}
|
|
165
|
-
| {enabled: 'active'},
|
|
166
|
-
) => boolean
|
|
167
|
-
}
|
|
168
|
-
send: (event: DecoratorButtonEvent) => void
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* @beta
|
|
173
|
-
* Manages the state, keyboard shortcuts and available events for a decorator
|
|
174
|
-
* button and sets up mutually exclusive decorator behaviors.
|
|
175
|
-
*/
|
|
176
|
-
export function useDecoratorButton(props: {
|
|
177
|
-
schemaType: ToolbarDecoratorSchemaType
|
|
178
|
-
}): DecoratorButton {
|
|
179
|
-
const editor = useEditor()
|
|
180
|
-
const [actorSnapshot, send] = useActor(decoratorButtonMachine, {
|
|
181
|
-
input: {
|
|
182
|
-
editor,
|
|
183
|
-
schemaType: props.schemaType,
|
|
184
|
-
},
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
useDecoratorKeyboardShortcut(props)
|
|
188
|
-
useMutuallyExclusiveDecorator(props)
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
snapshot: {
|
|
192
|
-
matches: (state) => actorSnapshot.matches(state),
|
|
193
|
-
},
|
|
194
|
-
send,
|
|
195
|
-
}
|
|
196
|
-
}
|