@portabletext/editor 1.44.0 → 1.44.2

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.
Files changed (55) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +3 -3
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/editor-provider.cjs +323 -490
  4. package/lib/_chunks-cjs/editor-provider.cjs.map +1 -1
  5. package/lib/_chunks-es/behavior.core.js +3 -3
  6. package/lib/_chunks-es/behavior.core.js.map +1 -1
  7. package/lib/_chunks-es/editor-provider.js +325 -492
  8. package/lib/_chunks-es/editor-provider.js.map +1 -1
  9. package/lib/behaviors/index.cjs +2 -2
  10. package/lib/behaviors/index.cjs.map +1 -1
  11. package/lib/behaviors/index.d.cts +8390 -16283
  12. package/lib/behaviors/index.d.ts +8390 -16283
  13. package/lib/behaviors/index.js +4 -4
  14. package/lib/behaviors/index.js.map +1 -1
  15. package/lib/index.cjs +2 -2
  16. package/lib/index.cjs.map +1 -1
  17. package/lib/index.d.cts +2237 -15969
  18. package/lib/index.d.ts +2237 -15969
  19. package/lib/index.js +2 -2
  20. package/lib/index.js.map +1 -1
  21. package/lib/plugins/index.d.cts +2088 -15821
  22. package/lib/plugins/index.d.ts +2088 -15821
  23. package/lib/selectors/index.d.cts +1738 -15472
  24. package/lib/selectors/index.d.ts +1738 -15472
  25. package/lib/utils/index.d.cts +1738 -15472
  26. package/lib/utils/index.d.ts +1738 -15472
  27. package/package.json +2 -2
  28. package/src/behavior-actions/behavior.actions.ts +1 -39
  29. package/src/behaviors/behavior.abstract.annotation.ts +26 -0
  30. package/src/behaviors/behavior.abstract.decorator.ts +47 -0
  31. package/src/behaviors/{behavior.internal.insert.ts → behavior.abstract.insert.ts} +1 -1
  32. package/src/behaviors/{behavior.internal.list-item.ts → behavior.abstract.list-item.ts} +1 -1
  33. package/src/behaviors/behavior.abstract.move.ts +78 -0
  34. package/src/behaviors/{behavior.internal.select.ts → behavior.abstract.select.ts} +1 -1
  35. package/src/behaviors/{behavior.internal.style.ts → behavior.abstract.style.ts} +1 -1
  36. package/src/behaviors/behavior.code-editor.ts +13 -8
  37. package/src/behaviors/behavior.default.ts +15 -78
  38. package/src/behaviors/behavior.perform-event.ts +4 -4
  39. package/src/behaviors/behavior.types.action.ts +3 -3
  40. package/src/behaviors/behavior.types.behavior.ts +4 -3
  41. package/src/behaviors/behavior.types.event.ts +164 -160
  42. package/src/editor/components/Leaf.tsx +2 -2
  43. package/src/editor/create-editor.ts +37 -11
  44. package/src/editor/editor-machine.ts +4 -76
  45. package/src/editor/editor-selector.ts +5 -2
  46. package/src/editor/editor-snapshot.ts +2 -7
  47. package/src/editor/plugins/create-with-event-listeners.ts +1 -64
  48. package/src/editor/plugins/createWithEditableAPI.ts +0 -30
  49. package/src/editor/plugins/createWithPortableTextMarkModel.ts +0 -29
  50. package/src/editor/plugins/with-plugins.ts +1 -4
  51. package/src/internal-utils/slate-children-to-blocks.ts +49 -0
  52. package/src/internal-utils/slate-utils.ts +6 -8
  53. package/src/type-utils.ts +2 -0
  54. package/src/behavior-actions/behavior.action.move.block-down.ts +0 -48
  55. package/src/behavior-actions/behavior.action.move.block-up.ts +0 -53
@@ -12,11 +12,7 @@ import {
12
12
  type Snapshot,
13
13
  } from 'xstate'
14
14
  import type {Behavior} from '../behaviors/behavior.types.behavior'
15
- import type {
16
- CustomBehaviorEvent,
17
- ExternalBehaviorEvent,
18
- SyntheticBehaviorEvent,
19
- } from '../behaviors/behavior.types.event'
15
+ import type {ExternalBehaviorEvent} from '../behaviors/behavior.types.event'
20
16
  import {coreConverters} from '../converters/converters.core'
21
17
  import {compileType} from '../internal-utils/schema'
22
18
  import type {EditableAPI} from '../types/editor'
@@ -63,11 +59,7 @@ export type EditorConfig = {
63
59
  /**
64
60
  * @public
65
61
  */
66
- export type EditorEvent =
67
- | ExternalEditorEvent
68
- | ExternalBehaviorEvent
69
- | SyntheticBehaviorEvent
70
- | CustomBehaviorEvent
62
+ export type EditorEvent = ExternalEditorEvent | ExternalBehaviorEvent
71
63
 
72
64
  /**
73
65
  * @public
@@ -154,7 +146,41 @@ function createInternalEditorFromActor(
154
146
  }
155
147
  },
156
148
  send: (event) => {
157
- editorActor.send(event)
149
+ switch (event.type) {
150
+ case 'add behavior':
151
+ case 'remove behavior':
152
+ case 'update behaviors':
153
+ case 'update key generator':
154
+ case 'update readOnly':
155
+ case 'patches':
156
+ case 'update value':
157
+ case 'update schema':
158
+ case 'update maxBlocks':
159
+ editorActor.send(event)
160
+ break
161
+
162
+ case 'insert.block object':
163
+ editorActor.send({
164
+ type: 'behavior event',
165
+ behaviorEvent: {
166
+ type: 'insert.block',
167
+ block: {
168
+ _type: event.blockObject.name,
169
+ ...(event.blockObject.value ?? {}),
170
+ },
171
+ placement: event.placement,
172
+ },
173
+ editor: slateEditor.instance,
174
+ })
175
+ break
176
+
177
+ default:
178
+ editorActor.send({
179
+ type: 'behavior event',
180
+ behaviorEvent: event,
181
+ editor: slateEditor.instance,
182
+ })
183
+ }
158
184
  },
159
185
  on: (event, listener) => {
160
186
  const subscription = editorActor.on(event, (event) => {
@@ -13,13 +13,7 @@ import {coreBehaviors} from '../behaviors/behavior.core'
13
13
  import {defaultBehaviors} from '../behaviors/behavior.default'
14
14
  import {performEvent} from '../behaviors/behavior.perform-event'
15
15
  import type {Behavior} from '../behaviors/behavior.types.behavior'
16
- import type {
17
- CustomBehaviorEvent,
18
- ExternalBehaviorEvent,
19
- InternalBehaviorEvent,
20
- NativeBehaviorEvent,
21
- SyntheticBehaviorEvent,
22
- } from '../behaviors/behavior.types.event'
16
+ import type {BehaviorEvent} from '../behaviors/behavior.types.event'
23
17
  import type {Converter} from '../converters/converter.types'
24
18
  import type {EventPosition} from '../internal-utils/event-position'
25
19
  import type {NamespaceEvent} from '../type-utils'
@@ -167,6 +161,7 @@ export type HasTag = ReturnType<EditorActor['getSnapshot']>['hasTag']
167
161
  * @internal
168
162
  */
169
163
  export type InternalEditorEvent =
164
+ | ExternalEditorEvent
170
165
  | {
171
166
  type: 'normalizing'
172
167
  }
@@ -178,28 +173,15 @@ export type InternalEditorEvent =
178
173
  }
179
174
  | {
180
175
  type: 'behavior event'
181
- behaviorEvent:
182
- | InternalBehaviorEvent
183
- | SyntheticBehaviorEvent
184
- | NativeBehaviorEvent
176
+ behaviorEvent: BehaviorEvent
185
177
  editor: PortableTextSlateEditor
186
178
  defaultActionCallback?: () => void
187
179
  nativeEvent?: {preventDefault: () => void}
188
180
  }
189
- | {
190
- type: 'custom behavior event'
191
- behaviorEvent: CustomBehaviorEvent
192
- editor: PortableTextSlateEditor
193
- nativeEvent?: {preventDefault: () => void}
194
- }
195
- | CustomBehaviorEvent
196
- | ExternalBehaviorEvent
197
- | ExternalEditorEvent
198
181
  | MutationEvent
199
182
  | InternalPatchEvent
200
183
  | NamespaceEvent<EditorEmittedEvent, 'notify'>
201
184
  | NamespaceEvent<UnsetEvent, 'notify'>
202
- | SyntheticBehaviorEvent
203
185
  | {
204
186
  type: 'dragstart'
205
187
  origin: Pick<EventPosition, 'selection'>
@@ -213,15 +195,9 @@ export type InternalEditorEvent =
213
195
  */
214
196
  export type InternalEditorEmittedEvent =
215
197
  | EditorEmittedEvent
216
- | ExternalBehaviorEvent
217
198
  | InternalPatchEvent
218
199
  | PatchesEvent
219
200
  | UnsetEvent
220
- | {
221
- type: 'custom.*'
222
- event: CustomBehaviorEvent
223
- }
224
- | SyntheticBehaviorEvent
225
201
 
226
202
  /**
227
203
  * @internal
@@ -318,7 +294,7 @@ export const editorMachine = setup({
318
294
  pendingEvents: [],
319
295
  }),
320
296
  'handle behavior event': ({context, event, self}) => {
321
- assertEvent(event, ['behavior event', 'custom behavior event'])
297
+ assertEvent(event, ['behavior event'])
322
298
 
323
299
  performEvent({
324
300
  behaviors: [...context.behaviors.values(), ...defaultBehaviors],
@@ -447,54 +423,6 @@ export const editorMachine = setup({
447
423
  'behavior event': {
448
424
  actions: 'handle behavior event',
449
425
  },
450
- 'custom behavior event': {
451
- actions: 'handle behavior event',
452
- },
453
- 'annotation.*': {
454
- actions: emit(({event}) => event),
455
- },
456
- 'block.*': {
457
- actions: emit(({event}) => event),
458
- },
459
- 'blur': {
460
- actions: emit(({event}) => event),
461
- },
462
- 'custom.*': {
463
- actions: emit(({event}) => ({type: 'custom.*', event})),
464
- },
465
- 'decorator.*': {
466
- actions: emit(({event}) => event),
467
- },
468
- 'delete.*': {
469
- actions: emit(({event}) => event),
470
- },
471
- 'focus': {
472
- actions: emit(({event}) => event),
473
- },
474
- 'history.*': {
475
- actions: emit(({event}) => event),
476
- },
477
- 'insert.*': {
478
- actions: emit(({event}) => event),
479
- },
480
- 'list item.*': {
481
- actions: emit(({event}) => event),
482
- },
483
- 'move.*': {
484
- actions: emit(({event}) => event),
485
- },
486
- 'select': {
487
- actions: emit(({event}) => event),
488
- },
489
- 'select.*': {
490
- actions: emit(({event}) => event),
491
- },
492
- 'style.*': {
493
- actions: emit(({event}) => event),
494
- },
495
- 'text block.*': {
496
- actions: emit(({event}) => event),
497
- },
498
426
  },
499
427
  initial: 'idle',
500
428
  states: {
@@ -1,10 +1,10 @@
1
1
  import {useSelector} from '@xstate/react'
2
+ import {slateChildrenToBlocks} from '../internal-utils/slate-children-to-blocks'
2
3
  import type {PortableTextSlateEditor} from '../types/editor'
3
4
  import type {Editor, InternalEditor} from './create-editor'
4
5
  import type {EditorActor} from './editor-machine'
5
6
  import type {EditorSnapshot} from './editor-snapshot'
6
7
  import {getActiveDecorators} from './get-active-decorators'
7
- import {getValue} from './get-value'
8
8
 
9
9
  function defaultCompare<T>(a: T, b: T) {
10
10
  return a === b
@@ -77,7 +77,10 @@ export function getEditorSnapshot({
77
77
  readOnly: editorActorSnapshot.matches({'edit mode': 'read only'}),
78
78
  schema: editorActorSnapshot.context.schema,
79
79
  selection: editorActorSnapshot.context.selection,
80
- value: getValue({editorActorSnapshot, slateEditorInstance}),
80
+ value: slateChildrenToBlocks(
81
+ editorActorSnapshot.context.schema,
82
+ slateEditorInstance.children,
83
+ ),
81
84
  },
82
85
  beta: {
83
86
  hasTag: (tag) => editorActorSnapshot.hasTag(tag),
@@ -2,8 +2,7 @@ import type {PortableTextBlock} from '@sanity/types'
2
2
  import type {Converter} from '../converters/converter.types'
3
3
  import type {EventPosition} from '../internal-utils/event-position'
4
4
  import {toPortableTextRange} from '../internal-utils/ranges'
5
- import {fromSlateValue} from '../internal-utils/values'
6
- import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
5
+ import {slateChildrenToBlocks} from '../internal-utils/slate-children-to-blocks'
7
6
  import type {EditorSelection, PortableTextSlateEditor} from '../types/editor'
8
7
  import type {EditorSchema} from './define-schema'
9
8
  import type {HasTag} from './editor-machine'
@@ -62,11 +61,7 @@ export function createEditorSnapshot({
62
61
  }
63
62
  | undefined
64
63
  }) {
65
- const value = fromSlateValue(
66
- editor.children,
67
- schema.block.name,
68
- KEY_TO_VALUE_ELEMENT.get(editor),
69
- )
64
+ const value = slateChildrenToBlocks(schema, editor.children)
70
65
  const selection = toPortableTextRange(value, editor.selection, schema)
71
66
 
72
67
  const context = {
@@ -7,75 +7,12 @@ import {KEY_TO_VALUE_ELEMENT} from '../../internal-utils/weakMaps'
7
7
  import type {EditorActor} from '../editor-machine'
8
8
  import {isApplyingBehaviorActions} from '../with-applying-behavior-actions'
9
9
 
10
- export function createWithEventListeners(
11
- editorActor: EditorActor,
12
- subscriptions: Array<() => () => void>,
13
- ) {
10
+ export function createWithEventListeners(editorActor: EditorActor) {
14
11
  return function withEventListeners(editor: Editor) {
15
12
  if (editorActor.getSnapshot().context.maxBlocks !== undefined) {
16
13
  return editor
17
14
  }
18
15
 
19
- subscriptions.push(() => {
20
- const subscription = editorActor.on('*', (event) => {
21
- switch (event.type) {
22
- // These events are not relevant for Behaviors
23
- case 'blurred':
24
- case 'done loading':
25
- case 'editable':
26
- case 'error':
27
- case 'focused':
28
- case 'invalid value':
29
- case 'loading':
30
- case 'mutation':
31
- case 'patch':
32
- case 'internal.patch':
33
- case 'patches':
34
- case 'read only':
35
- case 'ready':
36
- case 'selection':
37
- case 'value changed':
38
- case 'unset':
39
- break
40
-
41
- case 'custom.*':
42
- editorActor.send({
43
- type: 'custom behavior event',
44
- behaviorEvent: event.event,
45
- editor,
46
- })
47
- break
48
-
49
- case 'insert.block object':
50
- editorActor.send({
51
- type: 'behavior event',
52
- behaviorEvent: {
53
- type: 'insert.block',
54
- block: {
55
- _type: event.blockObject.name,
56
- ...(event.blockObject.value ?? {}),
57
- },
58
- placement: event.placement,
59
- },
60
- editor,
61
- })
62
- break
63
-
64
- default:
65
- editorActor.send({
66
- type: 'behavior event',
67
- behaviorEvent: event,
68
- editor,
69
- })
70
- break
71
- }
72
- })
73
-
74
- return () => {
75
- subscription.unsubscribe()
76
- }
77
- })
78
-
79
16
  const {deleteBackward, deleteForward, insertBreak, insertText, select} =
80
17
  editor
81
18
 
@@ -899,33 +899,3 @@ export const removeAnnotationActionImplementation: BehaviorActionImplementation<
899
899
  }
900
900
  }
901
901
  }
902
-
903
- export const toggleAnnotationActionImplementation: BehaviorActionImplementation<
904
- 'annotation.toggle',
905
- AddedAnnotationPaths | undefined
906
- > = ({context, action}) => {
907
- const isActive = isAnnotationActive({
908
- editor: action.editor,
909
- annotation: {name: action.annotation.name},
910
- })
911
-
912
- if (isActive) {
913
- removeAnnotationActionImplementation({
914
- context,
915
- action: {
916
- type: 'annotation.remove',
917
- annotation: action.annotation,
918
- editor: action.editor,
919
- },
920
- })
921
- } else {
922
- return addAnnotationActionImplementation({
923
- context,
924
- action: {
925
- type: 'annotation.add',
926
- annotation: action.annotation,
927
- editor: action.editor,
928
- },
929
- })
930
- }
931
- }
@@ -8,7 +8,6 @@ import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit'
8
8
  import type {PortableTextObject, PortableTextSpan} from '@sanity/types'
9
9
  import {isEqual, uniq} from 'lodash'
10
10
  import {Editor, Element, Node, Path, Range, Text, Transforms} from 'slate'
11
- import {decoratorAddActionImplementation} from '../../behavior-actions/behavior.action.decorator.add'
12
11
  import type {BehaviorActionImplementation} from '../../behavior-actions/behavior.actions'
13
12
  import {debugWithName} from '../../internal-utils/debug'
14
13
  import {getNextSpan, getPreviousSpan} from '../../internal-utils/sibling-utils'
@@ -778,31 +777,3 @@ export function isDecoratorActive({
778
777
  }.marks || []
779
778
  ).includes(decorator)
780
779
  }
781
-
782
- export const toggleDecoratorActionImplementation: BehaviorActionImplementation<
783
- 'decorator.toggle'
784
- > = ({context, action}) => {
785
- const isActive = isDecoratorActive({
786
- editor: action.editor,
787
- decorator: action.decorator,
788
- })
789
-
790
- if (isActive) {
791
- removeDecoratorActionImplementation({
792
- context,
793
- action: {
794
- type: 'decorator.remove',
795
- editor: action.editor,
796
- decorator: action.decorator,
797
- },
798
- })
799
- } else {
800
- decoratorAddActionImplementation({
801
- context,
802
- action: {
803
- ...action,
804
- type: 'decorator.add',
805
- },
806
- })
807
- }
808
- }
@@ -69,10 +69,7 @@ export const withPlugins = <T extends Editor>(
69
69
  editorActor,
70
70
  schemaTypes,
71
71
  )
72
- const withEventListeners = createWithEventListeners(
73
- editorActor,
74
- options.subscriptions,
75
- )
72
+ const withEventListeners = createWithEventListeners(editorActor)
76
73
 
77
74
  // Ordering is important here, selection dealing last, data manipulation in the middle and core model stuff first.
78
75
  return withEventListeners(
@@ -0,0 +1,49 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {Descendant} from 'slate'
3
+ import type {EditorSchema} from '../editor/define-schema'
4
+
5
+ export function slateChildrenToBlocks(
6
+ schema: EditorSchema,
7
+ value: Array<Descendant>,
8
+ ): Array<PortableTextBlock> {
9
+ const blocks: Array<PortableTextBlock> = new Array(value.length)
10
+
11
+ for (let blockIndex = 0; blockIndex < value.length; blockIndex++) {
12
+ const descendant = value[blockIndex]
13
+
14
+ if (descendant._type !== schema.block.name) {
15
+ blocks[blockIndex] = {
16
+ _key: descendant._key,
17
+ _type: descendant._type,
18
+ ...('value' in descendant && typeof descendant.value === 'object'
19
+ ? descendant.value
20
+ : {}),
21
+ }
22
+ continue
23
+ }
24
+
25
+ const children = 'children' in descendant ? descendant.children : []
26
+ const processedChildren = new Array(children.length)
27
+
28
+ for (let childIndex = 0; childIndex < children.length; childIndex++) {
29
+ const child = children[childIndex]
30
+ processedChildren[childIndex] =
31
+ child._type === schema.span.name
32
+ ? child
33
+ : {
34
+ _key: child._key,
35
+ _type: child._type,
36
+ ...('value' in child && typeof child.value === 'object'
37
+ ? child.value
38
+ : {}),
39
+ }
40
+ }
41
+
42
+ blocks[blockIndex] = {
43
+ ...descendant,
44
+ children: processedChildren,
45
+ }
46
+ }
47
+
48
+ return blocks
49
+ }
@@ -12,14 +12,12 @@ export function getFocusBlock({
12
12
  return [undefined, undefined]
13
13
  }
14
14
 
15
- const focusBlock = Array.from(
16
- Editor.nodes(editor, {
17
- at: editor.selection.focus.path.slice(0, 1),
18
- match: (n) => !Editor.isEditor(n),
19
- }),
20
- ).at(0)
21
-
22
- return focusBlock ?? [undefined, undefined]
15
+ return (
16
+ Editor.node(editor, editor.selection.focus.path.slice(0, 1)) ?? [
17
+ undefined,
18
+ undefined,
19
+ ]
20
+ )
23
21
  }
24
22
 
25
23
  export function getFocusChild({
package/src/type-utils.ts CHANGED
@@ -25,3 +25,5 @@ export type NamespaceEvent<TEvent, TNamespace extends string> = TEvent extends {
25
25
  : TEvent[K]
26
26
  }
27
27
  : never
28
+
29
+ export type StrictExtract<T, U extends T> = U
@@ -1,48 +0,0 @@
1
- import {Path} from 'slate'
2
- import {toSlatePath} from '../internal-utils/paths'
3
- import {toPortableTextRange} from '../internal-utils/ranges'
4
- import {isKeyedSegment} from '../utils'
5
- import {moveBlockActionImplementation} from './behavior.action.move.block'
6
- import type {BehaviorActionImplementation} from './behavior.actions'
7
-
8
- export const moveBlockDownActionImplementation: BehaviorActionImplementation<
9
- 'move.block down'
10
- > = ({context, action}) => {
11
- const at = [toSlatePath(action.at, action.editor)[0]]
12
- const to = [Path.next(at)[0]]
13
- const selection = toPortableTextRange(
14
- action.editor.children,
15
- {
16
- anchor: {
17
- path: to,
18
- offset: 0,
19
- },
20
- focus: {
21
- path: to,
22
- offset: 0,
23
- },
24
- },
25
- context.schema,
26
- )
27
-
28
- const destinationBlockKey = selection
29
- ? isKeyedSegment(selection.focus.path[0])
30
- ? selection.focus.path[0]._key
31
- : undefined
32
- : undefined
33
-
34
- if (destinationBlockKey === undefined) {
35
- console.error('Could not find destination block key')
36
- return
37
- }
38
-
39
- moveBlockActionImplementation({
40
- context,
41
- action: {
42
- type: 'move.block',
43
- at: action.at,
44
- to: [{_key: destinationBlockKey}],
45
- editor: action.editor,
46
- },
47
- })
48
- }
@@ -1,53 +0,0 @@
1
- import {Path} from 'slate'
2
- import {toSlatePath} from '../internal-utils/paths'
3
- import {toPortableTextRange} from '../internal-utils/ranges'
4
- import {isKeyedSegment} from '../utils'
5
- import {moveBlockActionImplementation} from './behavior.action.move.block'
6
- import type {BehaviorActionImplementation} from './behavior.actions'
7
-
8
- export const moveBlockUpActionImplementation: BehaviorActionImplementation<
9
- 'move.block up'
10
- > = ({context, action}) => {
11
- const at = [toSlatePath(action.at, action.editor)[0]]
12
-
13
- if (!Path.hasPrevious(at)) {
14
- return
15
- }
16
-
17
- const to = [Path.previous(at)[0]]
18
- const selection = toPortableTextRange(
19
- action.editor.children,
20
- {
21
- anchor: {
22
- path: to,
23
- offset: 0,
24
- },
25
- focus: {
26
- path: to,
27
- offset: 0,
28
- },
29
- },
30
- context.schema,
31
- )
32
-
33
- const destinationBlockKey = selection
34
- ? isKeyedSegment(selection.focus.path[0])
35
- ? selection.focus.path[0]._key
36
- : undefined
37
- : undefined
38
-
39
- if (destinationBlockKey === undefined) {
40
- console.error('Could not find destination block key')
41
- return
42
- }
43
-
44
- moveBlockActionImplementation({
45
- context,
46
- action: {
47
- type: 'move.block',
48
- at: action.at,
49
- to: [{_key: destinationBlockKey}],
50
- editor: action.editor,
51
- },
52
- })
53
- }