@portabletext/toolbar 4.0.22 → 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.
@@ -1,186 +0,0 @@
1
- import {useEditor, type Editor, type ListSchemaType} from '@portabletext/editor'
2
- import * as selectors from '@portabletext/editor/selectors'
3
- import {useActor} from '@xstate/react'
4
- import {fromCallback, setup, type AnyEventObject} from 'xstate'
5
- import {disableListener, type DisableListenerEvent} from './disable-listener'
6
- import type {ToolbarListSchemaType} from './use-toolbar-schema'
7
-
8
- const activeListener = fromCallback<
9
- AnyEventObject,
10
- {editor: Editor; schemaType: ListSchemaType},
11
- {type: 'set active'} | {type: 'set inactive'}
12
- >(({input, sendBack}) => {
13
- // Send back the initial state
14
- if (
15
- selectors.isActiveListItem(input.schemaType.name)(
16
- input.editor.getSnapshot(),
17
- )
18
- ) {
19
- sendBack({type: 'set active'})
20
- } else {
21
- sendBack({type: 'set inactive'})
22
- }
23
-
24
- return input.editor.on('*', () => {
25
- const snapshot = input.editor.getSnapshot()
26
-
27
- if (selectors.isActiveListItem(input.schemaType.name)(snapshot)) {
28
- sendBack({type: 'set active'})
29
- } else {
30
- sendBack({type: 'set inactive'})
31
- }
32
- }).unsubscribe
33
- })
34
-
35
- const listButtonMachine = setup({
36
- types: {
37
- context: {} as {
38
- editor: Editor
39
- schemaType: ListSchemaType
40
- },
41
- input: {} as {
42
- editor: Editor
43
- schemaType: ListSchemaType
44
- },
45
- events: {} as DisableListenerEvent | ListButtonEvent,
46
- },
47
- actions: {
48
- toggle: ({context, event}) => {
49
- if (event.type !== 'toggle') {
50
- return
51
- }
52
-
53
- context.editor.send({
54
- type: 'list item.toggle',
55
- listItem: context.schemaType.name,
56
- })
57
- context.editor.send({type: 'focus'})
58
- },
59
- },
60
- actors: {
61
- 'disable listener': disableListener,
62
- 'active listener': activeListener,
63
- },
64
- }).createMachine({
65
- id: 'list button',
66
- context: ({input}) => ({
67
- editor: input.editor,
68
- schemaType: input.schemaType,
69
- }),
70
- invoke: [
71
- {src: 'disable listener', input: ({context}) => ({editor: context.editor})},
72
- {
73
- src: 'active listener',
74
- input: ({context}) => ({
75
- editor: context.editor,
76
- schemaType: context.schemaType,
77
- }),
78
- },
79
- ],
80
- initial: 'disabled',
81
- states: {
82
- disabled: {
83
- initial: 'inactive',
84
- states: {
85
- inactive: {
86
- on: {
87
- 'enable': {
88
- target: '#list button.enabled.inactive',
89
- },
90
- 'set active': {
91
- target: 'active',
92
- },
93
- },
94
- },
95
- active: {
96
- on: {
97
- 'enable': {
98
- target: '#list button.enabled.active',
99
- },
100
- 'set inactive': {
101
- target: 'inactive',
102
- },
103
- },
104
- },
105
- },
106
- },
107
- enabled: {
108
- on: {
109
- toggle: {
110
- actions: ['toggle'],
111
- },
112
- },
113
- initial: 'inactive',
114
- states: {
115
- inactive: {
116
- on: {
117
- 'disable': {
118
- target: '#list button.disabled.inactive',
119
- },
120
- 'set active': {
121
- target: 'active',
122
- },
123
- },
124
- },
125
- active: {
126
- on: {
127
- 'disable': {
128
- target: '#list button.disabled.active',
129
- },
130
- 'set inactive': {
131
- target: 'inactive',
132
- },
133
- },
134
- },
135
- },
136
- },
137
- },
138
- })
139
-
140
- /**
141
- * @beta
142
- */
143
- export type ListButtonEvent = {
144
- type: 'toggle'
145
- }
146
-
147
- /**
148
- * @beta
149
- */
150
- export type ListButton = {
151
- snapshot: {
152
- matches: (
153
- state:
154
- | 'disabled'
155
- | 'enabled'
156
- | {disabled: 'inactive'}
157
- | {disabled: 'active'}
158
- | {enabled: 'inactive'}
159
- | {enabled: 'active'},
160
- ) => boolean
161
- }
162
- send: (event: ListButtonEvent) => void
163
- }
164
-
165
- /**
166
- * @beta
167
- * Manages the state, keyboard shortcuts and available events for a list button.
168
- */
169
- export function useListButton(props: {
170
- schemaType: ToolbarListSchemaType
171
- }): ListButton {
172
- const editor = useEditor()
173
- const [actorSnapshot, send] = useActor(listButtonMachine, {
174
- input: {
175
- editor,
176
- schemaType: props.schemaType,
177
- },
178
- })
179
-
180
- return {
181
- snapshot: {
182
- matches: (state) => actorSnapshot.matches(state),
183
- },
184
- send,
185
- }
186
- }
@@ -1,48 +0,0 @@
1
- import {useEditor} from '@portabletext/editor'
2
- import {defineBehavior, execute, raise} from '@portabletext/editor/behaviors'
3
- import {isActiveAnnotation} from '@portabletext/editor/selectors'
4
- import {useEffect} from 'react'
5
- import type {ToolbarAnnotationSchemaType} from './use-toolbar-schema'
6
-
7
- export function useMutuallyExclusiveAnnotation(props: {
8
- schemaType: ToolbarAnnotationSchemaType
9
- }) {
10
- const editor = useEditor()
11
-
12
- useEffect(() => {
13
- const mutuallyExclusive = props.schemaType.mutuallyExclusive
14
-
15
- if (!mutuallyExclusive) {
16
- return
17
- }
18
-
19
- return editor.registerBehavior({
20
- behavior: defineBehavior({
21
- on: 'annotation.add',
22
- guard: ({snapshot, event}) => {
23
- if (event.annotation.name !== props.schemaType.name) {
24
- return false
25
- }
26
-
27
- const activeMutuallyExclusive = mutuallyExclusive.filter(
28
- (annotation) =>
29
- isActiveAnnotation(annotation, {mode: 'partial'})(snapshot),
30
- )
31
-
32
- return {activeMutuallyExclusive}
33
- },
34
- actions: [
35
- ({event}, {activeMutuallyExclusive}) => [
36
- ...activeMutuallyExclusive.map((annotation) =>
37
- raise({
38
- type: 'annotation.remove',
39
- annotation: {name: annotation},
40
- }),
41
- ),
42
- execute(event),
43
- ],
44
- ],
45
- }),
46
- })
47
- }, [editor, props.schemaType.name, props.schemaType.mutuallyExclusive])
48
- }
@@ -1,36 +0,0 @@
1
- import {useEditor} from '@portabletext/editor'
2
- import {defineBehavior, forward, raise} from '@portabletext/editor/behaviors'
3
- import {useEffect} from 'react'
4
- import type {ToolbarDecoratorSchemaType} from './use-toolbar-schema'
5
-
6
- export function useMutuallyExclusiveDecorator(props: {
7
- schemaType: ToolbarDecoratorSchemaType
8
- }) {
9
- const editor = useEditor()
10
-
11
- useEffect(() => {
12
- const mutuallyExclusive = props.schemaType.mutuallyExclusive
13
-
14
- if (!mutuallyExclusive) {
15
- return
16
- }
17
-
18
- return editor.registerBehavior({
19
- behavior: defineBehavior({
20
- on: 'decorator.add',
21
- guard: ({event}) => event.decorator === props.schemaType.name,
22
- actions: [
23
- ({event}) => [
24
- forward(event),
25
- ...mutuallyExclusive.map((decorator) =>
26
- raise({
27
- type: 'decorator.remove',
28
- decorator,
29
- }),
30
- ),
31
- ],
32
- ],
33
- }),
34
- })
35
- }, [editor, props.schemaType.name, props.schemaType.mutuallyExclusive])
36
- }
@@ -1,105 +0,0 @@
1
- import {useEditor, type Editor} from '@portabletext/editor'
2
- import {defineBehavior, raise} from '@portabletext/editor/behaviors'
3
- import {useActorRef} from '@xstate/react'
4
- import {fromCallback, setup, type AnyEventObject} from 'xstate'
5
- import {disableListener, type DisableListenerEvent} from './disable-listener'
6
- import type {ToolbarStyleSchemaType} from './use-toolbar-schema'
7
-
8
- const styleKeyboardShortcutsListener = fromCallback<
9
- AnyEventObject,
10
- {editor: Editor; schemaTypes: ReadonlyArray<ToolbarStyleSchemaType>}
11
- >(({input}) => {
12
- const unregisterBehaviors = input.schemaTypes.flatMap((schemaType) => {
13
- const shortcut = schemaType.shortcut
14
-
15
- if (!shortcut) {
16
- return []
17
- }
18
-
19
- return [
20
- input.editor.registerBehavior({
21
- behavior: defineBehavior({
22
- on: 'keyboard.keydown',
23
- guard: ({event}) => shortcut.guard(event.originEvent),
24
- actions: [
25
- () => [raise({type: 'style.toggle', style: schemaType.name})],
26
- ],
27
- }),
28
- }),
29
- ]
30
- })
31
-
32
- return () => {
33
- for (const unregisterBehavior of unregisterBehaviors) {
34
- unregisterBehavior()
35
- }
36
- }
37
- })
38
-
39
- const styleKeyboardShortcutsMachine = setup({
40
- types: {
41
- context: {} as {
42
- editor: Editor
43
- schemaTypes: ReadonlyArray<ToolbarStyleSchemaType>
44
- },
45
- input: {} as {
46
- editor: Editor
47
- schemaTypes: ReadonlyArray<ToolbarStyleSchemaType>
48
- },
49
- events: {} as DisableListenerEvent | {type: 'style.toggle'},
50
- },
51
- actors: {
52
- 'disable listener': disableListener,
53
- 'style keyboard shortcuts listener': styleKeyboardShortcutsListener,
54
- },
55
- }).createMachine({
56
- id: 'style keyboard shortcuts',
57
- context: ({input}) => ({
58
- editor: input.editor,
59
- schemaTypes: input.schemaTypes,
60
- }),
61
- invoke: {
62
- src: 'disable listener',
63
- input: ({context}) => ({editor: context.editor}),
64
- },
65
- initial: 'disabled',
66
- states: {
67
- disabled: {
68
- on: {
69
- enable: {
70
- target: 'enabled',
71
- },
72
- },
73
- },
74
- enabled: {
75
- invoke: {
76
- src: 'style keyboard shortcuts listener',
77
- input: ({context}) => ({
78
- editor: context.editor,
79
- schemaTypes: context.schemaTypes,
80
- }),
81
- },
82
- on: {
83
- disable: {
84
- target: 'disabled',
85
- },
86
- },
87
- },
88
- },
89
- })
90
-
91
- /**
92
- * @beta
93
- * Registers keyboard shortcuts for a set of style schema types.
94
- */
95
- export function useStyleKeyboardShortcuts(props: {
96
- schemaTypes: ReadonlyArray<ToolbarStyleSchemaType>
97
- }) {
98
- const editor = useEditor()
99
- useActorRef(styleKeyboardShortcutsMachine, {
100
- input: {
101
- editor,
102
- schemaTypes: props.schemaTypes,
103
- },
104
- })
105
- }
@@ -1,154 +0,0 @@
1
- import {
2
- useEditor,
3
- type Editor,
4
- type StyleSchemaType,
5
- } from '@portabletext/editor'
6
- import * as selectors from '@portabletext/editor/selectors'
7
- import {useActor} from '@xstate/react'
8
- import {assign, fromCallback, setup, type AnyEventObject} from 'xstate'
9
- import {disableListener, type DisableListenerEvent} from './disable-listener'
10
- import {useStyleKeyboardShortcuts} from './use-style-keyboard-shortcuts'
11
- import type {ToolbarStyleSchemaType} from './use-toolbar-schema'
12
-
13
- type ActiveStyleListenerEvent = {
14
- type: 'set active style'
15
- style: StyleSchemaType['name'] | undefined
16
- }
17
-
18
- const activeListener = fromCallback<
19
- AnyEventObject,
20
- {editor: Editor},
21
- ActiveStyleListenerEvent
22
- >(({input, sendBack}) => {
23
- // Send back the initial state
24
- const activeStyle = selectors.getActiveStyle(input.editor.getSnapshot())
25
- sendBack({type: 'set active style', style: activeStyle})
26
-
27
- return input.editor.on('*', () => {
28
- const snapshot = input.editor.getSnapshot()
29
- const activeStyle = selectors.getActiveStyle(snapshot)
30
-
31
- sendBack({type: 'set active style', style: activeStyle})
32
- }).unsubscribe
33
- })
34
-
35
- const styleSelectorMachine = setup({
36
- types: {
37
- context: {} as {
38
- editor: Editor
39
- activeStyle: StyleSchemaType['name'] | undefined
40
- },
41
- input: {} as {
42
- editor: Editor
43
- },
44
- events: {} as
45
- | StyleSelectorEvent
46
- | DisableListenerEvent
47
- | ActiveStyleListenerEvent,
48
- },
49
- actors: {
50
- 'disable listener': disableListener,
51
- 'active listener': activeListener,
52
- },
53
- }).createMachine({
54
- id: 'style selector',
55
- context: ({input}) => ({
56
- editor: input.editor,
57
- activeStyle: undefined,
58
- }),
59
- invoke: [
60
- {
61
- src: 'disable listener',
62
- input: ({context}) => ({
63
- editor: context.editor,
64
- }),
65
- },
66
- {
67
- src: 'active listener',
68
- input: ({context}) => ({
69
- editor: context.editor,
70
- }),
71
- },
72
- ],
73
- on: {
74
- 'set active style': {
75
- guard: ({context, event}) => context.activeStyle !== event.style,
76
- actions: assign({
77
- activeStyle: ({event}) => event.style,
78
- }),
79
- },
80
- },
81
- initial: 'disabled',
82
- states: {
83
- disabled: {
84
- on: {
85
- enable: {
86
- target: 'enabled',
87
- },
88
- },
89
- },
90
- enabled: {
91
- on: {
92
- disable: {
93
- target: 'disabled',
94
- },
95
- toggle: {
96
- actions: [
97
- ({context, event}) => {
98
- context.editor.send({type: 'style.toggle', style: event.style})
99
- context.editor.send({type: 'focus'})
100
- },
101
- ],
102
- },
103
- },
104
- },
105
- },
106
- })
107
-
108
- /**
109
- * @beta
110
- */
111
- export type StyleSelectorEvent = {
112
- type: 'toggle'
113
- style: StyleSchemaType['name']
114
- }
115
-
116
- /**
117
- * @beta
118
- */
119
- export type StyleSelector = {
120
- snapshot: {
121
- matches: (state: 'disabled' | 'enabled') => boolean
122
- context: {
123
- activeStyle: StyleSchemaType['name'] | undefined
124
- }
125
- }
126
- send: (event: StyleSelectorEvent) => void
127
- }
128
-
129
- /**
130
- * @beta
131
- * Manages the state, keyboard shortcuts and available events for a style
132
- * selector.
133
- */
134
- export function useStyleSelector(props: {
135
- schemaTypes: ReadonlyArray<ToolbarStyleSchemaType>
136
- }): StyleSelector {
137
- const editor = useEditor()
138
- const [actorSnapshot, send] = useActor(styleSelectorMachine, {
139
- input: {
140
- editor,
141
- },
142
- })
143
- useStyleKeyboardShortcuts(props)
144
-
145
- return {
146
- snapshot: {
147
- matches: (state) => actorSnapshot.matches(state),
148
- context: {
149
- activeStyle: actorSnapshot.context.activeStyle,
150
- },
151
- },
152
- send,
153
- }
154
- }
@@ -1,166 +0,0 @@
1
- import {
2
- useEditor,
3
- useEditorSelector,
4
- type AnnotationDefinition,
5
- type AnnotationSchemaType,
6
- type BlockObjectSchemaType,
7
- type DecoratorDefinition,
8
- type DecoratorSchemaType,
9
- type InlineObjectSchemaType,
10
- type ListSchemaType,
11
- type StyleSchemaType,
12
- } from '@portabletext/editor'
13
- import type {KeyboardShortcut} from '@portabletext/keyboard-shortcuts'
14
-
15
- /**
16
- * @beta
17
- */
18
- export type ExtendDecoratorSchemaType = (
19
- decorator: DecoratorSchemaType,
20
- ) => ToolbarDecoratorSchemaType
21
-
22
- /**
23
- * @beta
24
- */
25
- export type ExtendAnnotationSchemaType = (
26
- annotation: AnnotationSchemaType,
27
- ) => ToolbarAnnotationSchemaType
28
-
29
- /**
30
- * @beta
31
- */
32
- export type ExtendListSchemaType = (
33
- list: ListSchemaType,
34
- ) => ToolbarListSchemaType
35
-
36
- /**
37
- * @beta
38
- */
39
- export type ExtendBlockObjectSchemaType = (
40
- blockObject: BlockObjectSchemaType,
41
- ) => ToolbarBlockObjectSchemaType
42
-
43
- /**
44
- * @beta
45
- */
46
- export type ExtendInlineObjectSchemaType = (
47
- inlineObject: InlineObjectSchemaType,
48
- ) => ToolbarInlineObjectSchemaType
49
-
50
- /**
51
- * @beta
52
- */
53
- export type ExtendStyleSchemaType = (
54
- style: StyleSchemaType,
55
- ) => ToolbarStyleSchemaType
56
-
57
- /**
58
- * @beta
59
- * Extend the editor's schema with default values, icons, shortcuts and more.
60
- * This makes it easier to use the schema to render toolbars, forms and other
61
- * UI components.
62
- */
63
- export function useToolbarSchema(props: {
64
- extendDecorator?: (
65
- decorator: DecoratorSchemaType,
66
- ) => ToolbarDecoratorSchemaType
67
- extendAnnotation?: (
68
- annotation: AnnotationSchemaType,
69
- ) => ToolbarAnnotationSchemaType
70
- extendList?: (list: ListSchemaType) => ToolbarListSchemaType
71
- extendBlockObject?: (
72
- blockObject: BlockObjectSchemaType,
73
- ) => ToolbarBlockObjectSchemaType
74
- extendInlineObject?: (
75
- inlineObject: InlineObjectSchemaType,
76
- ) => ToolbarInlineObjectSchemaType
77
- extendStyle?: (style: StyleSchemaType) => ToolbarStyleSchemaType
78
- }): ToolbarSchema {
79
- const editor = useEditor()
80
- const schema = useEditorSelector(
81
- editor,
82
- (snapshot) => snapshot.context.schema,
83
- )
84
-
85
- return {
86
- decorators: schema.decorators.map(
87
- (decorator) => props.extendDecorator?.(decorator) ?? decorator,
88
- ),
89
- annotations: schema.annotations.map(
90
- (annotation) => props.extendAnnotation?.(annotation) ?? annotation,
91
- ),
92
- lists: schema.lists.map((list) => props.extendList?.(list) ?? list),
93
- blockObjects: schema.blockObjects.map(
94
- (blockObject) => props.extendBlockObject?.(blockObject) ?? blockObject,
95
- ),
96
- inlineObjects: schema.inlineObjects.map(
97
- (inlineObject) =>
98
- props.extendInlineObject?.(inlineObject) ?? inlineObject,
99
- ),
100
- styles: schema.styles.map((style) => props.extendStyle?.(style) ?? style),
101
- }
102
- }
103
-
104
- /**
105
- * @beta
106
- */
107
- export type ToolbarSchema = {
108
- decorators?: ReadonlyArray<ToolbarDecoratorSchemaType>
109
- annotations?: ReadonlyArray<ToolbarAnnotationSchemaType>
110
- lists?: ReadonlyArray<ToolbarListSchemaType>
111
- blockObjects?: ReadonlyArray<ToolbarBlockObjectSchemaType>
112
- inlineObjects?: ReadonlyArray<ToolbarInlineObjectSchemaType>
113
- styles?: ReadonlyArray<ToolbarStyleSchemaType>
114
- }
115
-
116
- /**
117
- * @beta
118
- */
119
- export type ToolbarDecoratorSchemaType = DecoratorSchemaType & {
120
- icon?: React.ComponentType
121
- shortcut?: KeyboardShortcut
122
- mutuallyExclusive?: ReadonlyArray<DecoratorDefinition['name']>
123
- }
124
-
125
- /**
126
- * @beta
127
- */
128
- export type ToolbarAnnotationSchemaType = AnnotationSchemaType & {
129
- icon?: React.ComponentType
130
- defaultValues?: Record<string, unknown>
131
- shortcut?: KeyboardShortcut
132
- mutuallyExclusive?: ReadonlyArray<AnnotationDefinition['name']>
133
- }
134
-
135
- /**
136
- * @beta
137
- */
138
- export type ToolbarListSchemaType = ListSchemaType & {
139
- icon?: React.ComponentType
140
- }
141
-
142
- /**
143
- * @beta
144
- */
145
- export type ToolbarBlockObjectSchemaType = BlockObjectSchemaType & {
146
- icon?: React.ComponentType
147
- defaultValues?: Record<string, unknown>
148
- shortcut?: KeyboardShortcut
149
- }
150
-
151
- /**
152
- * @beta
153
- */
154
- export type ToolbarInlineObjectSchemaType = InlineObjectSchemaType & {
155
- icon?: React.ComponentType
156
- defaultValues?: Record<string, unknown>
157
- shortcut?: KeyboardShortcut
158
- }
159
-
160
- /**
161
- * @beta
162
- */
163
- export type ToolbarStyleSchemaType = StyleSchemaType & {
164
- icon?: React.ComponentType
165
- shortcut?: KeyboardShortcut
166
- }