@prosekit/extensions 0.14.0 → 0.14.1

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 (65) hide show
  1. package/dist/{drop-indicator-B_oMfeVP.js → drop-indicator-DJq8pF92.js} +1 -1
  2. package/dist/{drop-indicator-B_oMfeVP.js.map → drop-indicator-DJq8pF92.js.map} +1 -1
  3. package/dist/{file-iLVR0eM0.js → file-upload-I9m1EJAM.js} +1 -1
  4. package/dist/file-upload-I9m1EJAM.js.map +1 -0
  5. package/dist/{index-cp1u4e0e.d.ts → file-upload-dr3IXUty.d.ts} +1 -1
  6. package/dist/file-upload-dr3IXUty.d.ts.map +1 -0
  7. package/dist/{paste-rule-BaDghcaU.js → mark-paste-rule-n_2Ehmb5.js} +1 -1
  8. package/dist/mark-paste-rule-n_2Ehmb5.js.map +1 -0
  9. package/dist/{mark-rule-CYe8zk4q.js → mark-rule-CUnXwBuy.js} +1 -1
  10. package/dist/{mark-rule-CYe8zk4q.js.map → mark-rule-CUnXwBuy.js.map} +1 -1
  11. package/dist/prosekit-extensions-blockquote.js +1 -1
  12. package/dist/prosekit-extensions-bold.js +1 -1
  13. package/dist/prosekit-extensions-code-block.d.ts +1 -1
  14. package/dist/prosekit-extensions-code-block.js +2 -2
  15. package/dist/prosekit-extensions-code.js +1 -1
  16. package/dist/prosekit-extensions-drop-indicator.js +1 -1
  17. package/dist/prosekit-extensions-enter-rule.d.ts +6 -78
  18. package/dist/prosekit-extensions-enter-rule.d.ts.map +1 -1
  19. package/dist/prosekit-extensions-enter-rule.js +37 -2
  20. package/dist/prosekit-extensions-enter-rule.js.map +1 -0
  21. package/dist/prosekit-extensions-file.d.ts +2 -2
  22. package/dist/prosekit-extensions-file.js +1 -1
  23. package/dist/prosekit-extensions-heading.js +1 -1
  24. package/dist/prosekit-extensions-horizontal-rule.js +1 -1
  25. package/dist/prosekit-extensions-image.d.ts +2 -1
  26. package/dist/prosekit-extensions-image.d.ts.map +1 -1
  27. package/dist/prosekit-extensions-image.js +1 -1
  28. package/dist/prosekit-extensions-input-rule.js +89 -2
  29. package/dist/prosekit-extensions-input-rule.js.map +1 -0
  30. package/dist/prosekit-extensions-italic.js +1 -1
  31. package/dist/prosekit-extensions-link.js +4 -4
  32. package/dist/prosekit-extensions-list.js +2 -2
  33. package/dist/prosekit-extensions-mark-rule.js +1 -1
  34. package/dist/prosekit-extensions-math.d.ts +154 -0
  35. package/dist/prosekit-extensions-math.d.ts.map +1 -0
  36. package/dist/prosekit-extensions-math.js +104 -0
  37. package/dist/prosekit-extensions-math.js.map +1 -0
  38. package/dist/prosekit-extensions-paste-rule.js +1 -1
  39. package/dist/prosekit-extensions-placeholder.js +1 -1
  40. package/dist/prosekit-extensions-strike.js +1 -1
  41. package/dist/prosekit-extensions-table.js +1 -1
  42. package/dist/prosekit-extensions-yjs.d.ts.map +1 -1
  43. package/dist/shiki-highlighter-chunk.d.ts +19 -2
  44. package/dist/shiki-highlighter-chunk.d.ts.map +1 -0
  45. package/dist/{table-4oHfV-Ql.js → table-UJVYsrB7.js} +2 -2
  46. package/dist/{table-4oHfV-Ql.js.map → table-UJVYsrB7.js.map} +1 -1
  47. package/package.json +19 -8
  48. package/src/enter-rule/index.ts +18 -191
  49. package/src/math/index.ts +22 -0
  50. package/src/math/math-block.ts +89 -0
  51. package/src/math/math-inline.ts +89 -0
  52. package/src/math/math-plugin.ts +8 -0
  53. package/src/math/math.ts +39 -0
  54. package/src/testing/index.ts +3 -0
  55. package/src/testing/katex.ts +9 -0
  56. package/src/yjs/yjs-types.ts +0 -2
  57. package/dist/enter-rule-D-p4ykfv.js +0 -96
  58. package/dist/enter-rule-D-p4ykfv.js.map +0 -1
  59. package/dist/file-iLVR0eM0.js.map +0 -1
  60. package/dist/index-cp1u4e0e.d.ts.map +0 -1
  61. package/dist/input-rule-COGr_GBb.js +0 -90
  62. package/dist/input-rule-COGr_GBb.js.map +0 -1
  63. package/dist/paste-rule-BaDghcaU.js.map +0 -1
  64. package/dist/shiki-highlighter-chunk-DNNm2Vow.d.ts +0 -19
  65. package/dist/shiki-highlighter-chunk-DNNm2Vow.d.ts.map +0 -1
@@ -1,104 +1,28 @@
1
+ import { defineFacet, defineFacetPayload, pluginFacet, type PlainExtension, type PluginPayload } from '@prosekit/core'
1
2
  import {
2
- defineFacet,
3
- defineFacetPayload,
4
- getNodeType,
5
- isTextSelection,
6
- maybeRun,
7
- OBJECT_REPLACEMENT_CHARACTER,
8
- pluginFacet,
9
- type PlainExtension,
10
- type PluginPayload,
11
- } from '@prosekit/core'
12
- import { keydownHandler } from '@prosekit/pm/keymap'
13
- import type { Attrs, NodeType } from '@prosekit/pm/model'
14
- import { PluginKey, ProseMirrorPlugin, type Command, type EditorState, type Transaction } from '@prosekit/pm/state'
15
- import type { EditorView } from '@prosekit/pm/view'
3
+ createEnterRulePlugin,
4
+ createTextBlockEnterRule,
5
+ type EnterRule,
6
+ type EnterRuleHandler,
7
+ type EnterRuleHandlerOptions,
8
+ type TextBlockEnterRuleOptions as _TextBlockEnterRuleOptions,
9
+ } from 'prosemirror-enter-rules'
16
10
 
17
- /**
18
- * @public
19
- *
20
- * Options for {@link EnterRuleHandler}.
21
- */
22
- export interface EnterRuleHandlerOptions {
23
- /**
24
- * The current editor state.
25
- */
26
- state: EditorState
27
-
28
- /**
29
- * The start position of the matched text.
30
- */
31
- from: number
32
-
33
- /**
34
- * The end position of the matched text.
35
- */
36
- to: number
37
-
38
- /**
39
- * The matched result from the regular expression.
40
- */
41
- match: RegExpExecArray
42
- }
43
-
44
- /**
45
- * @public
46
- */
47
- export type EnterRuleHandler = (options: EnterRuleHandlerOptions) => Transaction | null
11
+ export type { EnterRuleHandler, EnterRuleHandlerOptions }
48
12
 
49
13
  /**
50
14
  * Options for {@link defineEnterRule}.
51
15
  *
52
16
  * @public
53
17
  */
54
- export type EnterRuleOptions = {
55
- /**
56
- * The regular expression to match against. It should end with `$`.
57
- */
58
- regex: RegExp
59
-
60
- /**
61
- * A function to be called when an enter rule is triggered.
62
- */
63
- handler: EnterRuleHandler
64
-
65
- /**
66
- * Whether to stop further handlers from being called if this rule is triggered.
67
- *
68
- * @default false
69
- */
70
- stop?: boolean
71
- }
18
+ export type EnterRuleOptions = EnterRule
72
19
 
73
20
  /**
74
21
  * Options for {@link defineTextBlockEnterRule}.
75
22
  *
76
23
  * @public
77
24
  */
78
- export interface TextBlockEnterRuleOptions {
79
- /**
80
- * The regular expression to match against. It should end with `$`.
81
- */
82
- regex: RegExp
83
-
84
- /**
85
- * The node type to replace the matched text with.
86
- */
87
- type: string | NodeType
88
-
89
- /**
90
- * Attributes to set on the node. If a function is provided, it will be called
91
- * with the matched result from the regular expression.
92
- */
93
- attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null)
94
-
95
- /**
96
- * Whether to stop further handlers from being called if this rule is triggered.
97
- *
98
- * @default true
99
- */
100
- stop?: boolean
101
- }
25
+ export type TextBlockEnterRuleOptions = _TextBlockEnterRuleOptions
102
26
 
103
27
  /**
104
28
  * Defines an enter rule. An enter rule applies when the text directly in front of
@@ -109,13 +33,8 @@ export interface TextBlockEnterRuleOptions {
109
33
  *
110
34
  * @public
111
35
  */
112
- export function defineEnterRule({
113
- regex,
114
- handler,
115
- stop = false,
116
- }: EnterRuleOptions): PlainExtension {
117
- const rule: EnterRule = new EnterRule(regex, handler, stop)
118
- return defineFacetPayload(enterRule, [rule]) as PlainExtension
36
+ export function defineEnterRule(options: EnterRuleOptions): PlainExtension {
37
+ return defineFacetPayload(enterRuleFacet, [options]) as PlainExtension
119
38
  }
120
39
 
121
40
  /**
@@ -127,106 +46,14 @@ export function defineEnterRule({
127
46
  *
128
47
  * @public
129
48
  */
130
- export function defineTextBlockEnterRule({
131
- regex,
132
- type,
133
- attrs,
134
- stop = true,
135
- }: TextBlockEnterRuleOptions): PlainExtension {
136
- return defineEnterRule({
137
- regex,
138
- handler: ({ state, from, to, match }) => {
139
- const nodeType = getNodeType(state.schema, type)
140
- const $start = state.doc.resolve(from)
141
-
142
- if (
143
- !$start
144
- .node(-1)
145
- .canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)
146
- ) {
147
- return null
148
- }
149
-
150
- const nodeAttrs = maybeRun(attrs, match)
151
- return state.tr
152
- .delete(from, to)
153
- .setBlockType(from, from, nodeType, nodeAttrs)
154
- },
155
- stop,
156
- })
157
- }
158
-
159
- /**
160
- * @internal
161
- */
162
- class EnterRule {
163
- constructor(
164
- readonly regex: RegExp,
165
- readonly handler: EnterRuleHandler,
166
- readonly stop: boolean,
167
- ) {}
49
+ export function defineTextBlockEnterRule(options: TextBlockEnterRuleOptions): PlainExtension {
50
+ return defineEnterRule(createTextBlockEnterRule(options))
168
51
  }
169
52
 
170
- const enterRule = defineFacet<EnterRule, PluginPayload>({
171
- reduce: () => {
172
- let rules: EnterRule[] = []
173
-
174
- const command: Command = (state, dispatch, view) => {
175
- if (!view) return false
176
- return execRules(view, rules, dispatch)
177
- }
178
- const handler = keydownHandler({ Enter: command })
179
- const plugin = new ProseMirrorPlugin({
180
- key: new PluginKey('prosekit-enter-rule'),
181
- props: { handleKeyDown: handler },
182
- })
183
-
184
- return function reducer(inputs) {
185
- rules = inputs
186
- return plugin
187
- }
53
+ const enterRuleFacet = defineFacet<EnterRule, PluginPayload>({
54
+ reducer: (rules: EnterRule[]): PluginPayload => {
55
+ return createEnterRulePlugin({ rules })
188
56
  },
189
57
 
190
58
  parent: pluginFacet,
191
59
  })
192
-
193
- function execRules(
194
- view: EditorView,
195
- rules: readonly EnterRule[],
196
- dispatch?: (tr: Transaction) => void,
197
- ): boolean {
198
- if (view.composing) return false
199
- const state = view.state
200
- const selection = state.selection
201
- if (!isTextSelection(selection)) return false
202
- const $cursor = selection.$cursor
203
- if (!$cursor || $cursor.parent.type.spec.code) return false
204
-
205
- const textBefore = $cursor.parent.textBetween(
206
- Math.max(0, $cursor.parentOffset - MAX_MATCH),
207
- $cursor.parentOffset,
208
- null,
209
- OBJECT_REPLACEMENT_CHARACTER,
210
- )
211
-
212
- for (const rule of rules) {
213
- rule.regex.lastIndex = 0
214
- const match = rule.regex.exec(textBefore)
215
- const tr = match
216
- && rule.handler({
217
- state,
218
- from: $cursor.pos - match[0].length,
219
- to: $cursor.pos,
220
- match,
221
- })
222
- if (!tr) continue
223
- dispatch?.(tr)
224
-
225
- if (rule.stop) {
226
- return true
227
- }
228
- }
229
- return false
230
- }
231
-
232
- const MAX_MATCH = 200
@@ -0,0 +1,22 @@
1
+ export { defineMath, type MathExtension, type MathOptions } from './math'
2
+ export {
3
+ defineMathBlock,
4
+ defineMathBlockEnterRule,
5
+ defineMathBlockSpec,
6
+ defineMathBlockView,
7
+ type MathBlockExtension,
8
+ type MathBlockOptions,
9
+ type MathBlockSpecExtension,
10
+ type MathBlockViewOptions,
11
+ } from './math-block'
12
+ export {
13
+ defineMathInline,
14
+ defineMathInlineInputRule,
15
+ defineMathInlineSpec,
16
+ defineMathInlineView,
17
+ type MathInlineExtension,
18
+ type MathInlineOptions,
19
+ type MathInlineSpecExtension,
20
+ type MathInlineViewOptions,
21
+ } from './math-inline'
22
+ export { defineMathPlugin } from './math-plugin'
@@ -0,0 +1,89 @@
1
+ import { defineNodeSpec, defineNodeView, union, type Extension, type PlainExtension, type Union } from '@prosekit/core'
2
+ import type { Attrs } from '@prosekit/pm/model'
3
+ import { createMathBlockView, mathBlockEnterRule, mathBlockSpec, type RenderMathBlock } from 'prosemirror-math'
4
+
5
+ import { defineEnterRule } from '../enter-rule'
6
+
7
+ /**
8
+ * @internal
9
+ */
10
+ export type MathBlockSpecExtension = Extension<{
11
+ Nodes: {
12
+ mathBlock: Attrs
13
+ }
14
+ }>
15
+
16
+ /**
17
+ * @internal
18
+ */
19
+ export function defineMathBlockSpec(): MathBlockSpecExtension {
20
+ return defineNodeSpec<'mathBlock', Attrs>({
21
+ ...mathBlockSpec,
22
+ name: 'mathBlock',
23
+ })
24
+ }
25
+
26
+ /**
27
+ * Options for {@link defineMathBlockView}.
28
+ *
29
+ * @internal
30
+ */
31
+ export interface MathBlockViewOptions {
32
+ /**
33
+ * The function to render the math block.
34
+ */
35
+ render: RenderMathBlock
36
+ }
37
+
38
+ /**
39
+ * Defines an extension that renders a math block using a custom node view.
40
+ *
41
+ * @param options
42
+ * @internal
43
+ */
44
+ export function defineMathBlockView({ render }: MathBlockViewOptions): Extension {
45
+ return defineNodeView({
46
+ name: 'mathBlock',
47
+ constructor: (node, view, getPos, decorations) => {
48
+ return createMathBlockView(render, node, decorations)
49
+ },
50
+ })
51
+ }
52
+
53
+ /**
54
+ * @internal
55
+ */
56
+ export function defineMathBlockEnterRule(): PlainExtension {
57
+ return defineEnterRule(mathBlockEnterRule)
58
+ }
59
+
60
+ /**
61
+ * Options for {@link defineMathBlock}.
62
+ *
63
+ * @internal
64
+ */
65
+ export interface MathBlockOptions {
66
+ /**
67
+ * The function to render the math block.
68
+ */
69
+ render: RenderMathBlock
70
+ }
71
+
72
+ /**
73
+ * @internal
74
+ */
75
+ export type MathBlockExtension = Union<[MathBlockSpecExtension]>
76
+
77
+ /**
78
+ * Defines node `mathBlock` and related functionalities.
79
+ *
80
+ * @param options
81
+ * @public
82
+ */
83
+ export function defineMathBlock(options: MathBlockOptions): MathBlockExtension {
84
+ return union(
85
+ defineMathBlockSpec(),
86
+ defineMathBlockView(options),
87
+ defineMathBlockEnterRule(),
88
+ )
89
+ }
@@ -0,0 +1,89 @@
1
+ import { defineNodeSpec, defineNodeView, union, type Extension, type PlainExtension, type Union } from '@prosekit/core'
2
+ import type { Attrs } from '@prosekit/pm/model'
3
+ import { createMathInlineInputRule, createMathInlineView, mathInlineSpec, type RenderMathInline } from 'prosemirror-math'
4
+
5
+ import { defineInputRule } from '../input-rule'
6
+
7
+ /**
8
+ * @internal
9
+ */
10
+ export type MathInlineSpecExtension = Extension<{
11
+ Nodes: {
12
+ mathInline: Attrs
13
+ }
14
+ }>
15
+
16
+ /**
17
+ * @internal
18
+ */
19
+ export function defineMathInlineSpec(): MathInlineSpecExtension {
20
+ return defineNodeSpec<'mathInline', Attrs>({
21
+ ...mathInlineSpec,
22
+ name: 'mathInline',
23
+ })
24
+ }
25
+
26
+ /**
27
+ * Options for {@link defineMathInlineView}.
28
+ *
29
+ * @internal
30
+ */
31
+ export interface MathInlineViewOptions {
32
+ /**
33
+ * The function to render the math inline.
34
+ */
35
+ render: RenderMathInline
36
+ }
37
+
38
+ /**
39
+ * Defines an extension that renders a math inline using a custom node view.
40
+ *
41
+ * @param options
42
+ * @internal
43
+ */
44
+ export function defineMathInlineView({ render }: MathInlineViewOptions): Extension {
45
+ return defineNodeView({
46
+ name: 'mathInline',
47
+ constructor: (node, view, getPos, decorations) => {
48
+ return createMathInlineView(render, node, decorations)
49
+ },
50
+ })
51
+ }
52
+
53
+ /**
54
+ * @internal
55
+ */
56
+ export function defineMathInlineInputRule(): PlainExtension {
57
+ return defineInputRule(createMathInlineInputRule('mathInline'))
58
+ }
59
+
60
+ /**
61
+ * Options for {@link defineMathInline}.
62
+ *
63
+ * @internal
64
+ */
65
+ export interface MathInlineOptions {
66
+ /**
67
+ * The function to render the math inline.
68
+ */
69
+ render: RenderMathInline
70
+ }
71
+
72
+ /**
73
+ * @internal
74
+ */
75
+ export type MathInlineExtension = Union<[MathInlineSpecExtension]>
76
+
77
+ /**
78
+ * Defines node `mathInline` and related functionalities.
79
+ *
80
+ * @param options
81
+ * @public
82
+ */
83
+ export function defineMathInline(options: MathInlineOptions): MathInlineExtension {
84
+ return union(
85
+ defineMathInlineSpec(),
86
+ defineMathInlineView(options),
87
+ defineMathInlineInputRule(),
88
+ )
89
+ }
@@ -0,0 +1,8 @@
1
+ import { definePlugin, type PlainExtension } from '@prosekit/core'
2
+ import { createCursorInsidePlugin } from 'prosemirror-math'
3
+
4
+ export function defineMathPlugin(): PlainExtension {
5
+ return definePlugin(
6
+ createCursorInsidePlugin(),
7
+ )
8
+ }
@@ -0,0 +1,39 @@
1
+ import { union, type Union } from '@prosekit/core'
2
+ import type { RenderMathBlock, RenderMathInline } from 'prosemirror-math'
3
+
4
+ import { defineMathBlock, type MathBlockExtension } from './math-block'
5
+ import { defineMathInline, type MathInlineExtension } from './math-inline'
6
+ import { defineMathPlugin } from './math-plugin'
7
+
8
+ /**
9
+ * @public
10
+ */
11
+ export type MathExtension = Union<[MathInlineExtension, MathBlockExtension]>
12
+
13
+ /**
14
+ * Options for {@link defineMath}.
15
+ *
16
+ * @public
17
+ */
18
+ export interface MathOptions {
19
+ /**
20
+ * The function to render the math block.
21
+ */
22
+ renderMathBlock: RenderMathBlock
23
+
24
+ /**
25
+ * The function to render the math inline.
26
+ */
27
+ renderMathInline: RenderMathInline
28
+ }
29
+
30
+ /**
31
+ * @public
32
+ */
33
+ export function defineMath(options: MathOptions): MathExtension {
34
+ return union(
35
+ defineMathBlock({ render: options.renderMathBlock }),
36
+ defineMathInline({ render: options.renderMathInline }),
37
+ defineMathPlugin(),
38
+ )
39
+ }
@@ -26,6 +26,7 @@ import { defineImage } from '../image'
26
26
  import { defineItalic } from '../italic'
27
27
  import { defineLink } from '../link'
28
28
  import { defineList, type ListAttrs } from '../list'
29
+ import { defineMath } from '../math'
29
30
  import { defineParagraph } from '../paragraph'
30
31
  import { defineStrike } from '../strike'
31
32
  import { defineTable } from '../table'
@@ -35,6 +36,7 @@ import { defineTextColor } from '../text-color'
35
36
  import { defineUnderline } from '../underline'
36
37
 
37
38
  import { readHtmlTextFromClipboard, readPlainTextFromClipboard } from './clipboard'
39
+ import { renderMathBlock, renderMathInline } from './katex'
38
40
 
39
41
  /**
40
42
  * @internal
@@ -63,6 +65,7 @@ export function defineTestExtension() {
63
65
  defineHorizontalRule(),
64
66
  defineHardBreak(),
65
67
  defineCodeBlock(),
68
+ defineMath({ renderMathBlock, renderMathInline }),
66
69
  )
67
70
  }
68
71
 
@@ -0,0 +1,9 @@
1
+ import { render } from 'katex'
2
+
3
+ export function renderMathBlock(text: string, element: HTMLElement) {
4
+ render(text, element, { displayMode: true, throwOnError: false, output: 'mathml' })
5
+ }
6
+
7
+ export function renderMathInline(text: string, element: HTMLElement) {
8
+ render(text, element, { displayMode: false, throwOnError: false, output: 'mathml' })
9
+ }
@@ -1,7 +1,5 @@
1
1
  import type { yCursorPlugin } from 'y-prosemirror'
2
2
 
3
- // TODO: Remove `import type { Awareness } from 'y-protocols/awareness'` from examples.
4
-
5
3
  /**
6
4
  * @internal
7
5
  *
@@ -1,96 +0,0 @@
1
- import { OBJECT_REPLACEMENT_CHARACTER, defineFacet, defineFacetPayload, getNodeType, isTextSelection, maybeRun, pluginFacet } from "@prosekit/core";
2
- import { PluginKey, ProseMirrorPlugin } from "@prosekit/pm/state";
3
- import { keydownHandler } from "@prosekit/pm/keymap";
4
-
5
- //#region src/enter-rule/index.ts
6
- /**
7
- * Defines an enter rule. An enter rule applies when the text directly in front of
8
- * the cursor matches `regex` and user presses Enter. The `regex` should end
9
- * with `$`.
10
- *
11
- * @param options
12
- *
13
- * @public
14
- */
15
- function defineEnterRule({ regex, handler, stop = false }) {
16
- return defineFacetPayload(enterRule, [new EnterRule(regex, handler, stop)]);
17
- }
18
- /**
19
- * Defines an enter rule that replaces the matched text with a block node.
20
- *
21
- * See also {@link defineEnterRule}.
22
- *
23
- * @param options
24
- *
25
- * @public
26
- */
27
- function defineTextBlockEnterRule({ regex, type, attrs, stop = true }) {
28
- return defineEnterRule({
29
- regex,
30
- handler: ({ state, from, to, match }) => {
31
- const nodeType = getNodeType(state.schema, type);
32
- const $start = state.doc.resolve(from);
33
- if (!$start.node(-1).canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)) return null;
34
- const nodeAttrs = maybeRun(attrs, match);
35
- return state.tr.delete(from, to).setBlockType(from, from, nodeType, nodeAttrs);
36
- },
37
- stop
38
- });
39
- }
40
- /**
41
- * @internal
42
- */
43
- var EnterRule = class {
44
- constructor(regex, handler, stop) {
45
- this.regex = regex;
46
- this.handler = handler;
47
- this.stop = stop;
48
- }
49
- };
50
- const enterRule = defineFacet({
51
- reduce: () => {
52
- let rules = [];
53
- const command = (state, dispatch, view) => {
54
- if (!view) return false;
55
- return execRules(view, rules, dispatch);
56
- };
57
- const handler = keydownHandler({ Enter: command });
58
- const plugin = new ProseMirrorPlugin({
59
- key: new PluginKey("prosekit-enter-rule"),
60
- props: { handleKeyDown: handler }
61
- });
62
- return function reducer(inputs) {
63
- rules = inputs;
64
- return plugin;
65
- };
66
- },
67
- parent: pluginFacet
68
- });
69
- function execRules(view, rules, dispatch) {
70
- if (view.composing) return false;
71
- const state = view.state;
72
- const selection = state.selection;
73
- if (!isTextSelection(selection)) return false;
74
- const $cursor = selection.$cursor;
75
- if (!$cursor || $cursor.parent.type.spec.code) return false;
76
- const textBefore = $cursor.parent.textBetween(Math.max(0, $cursor.parentOffset - MAX_MATCH), $cursor.parentOffset, null, OBJECT_REPLACEMENT_CHARACTER);
77
- for (const rule of rules) {
78
- rule.regex.lastIndex = 0;
79
- const match = rule.regex.exec(textBefore);
80
- const tr = match && rule.handler({
81
- state,
82
- from: $cursor.pos - match[0].length,
83
- to: $cursor.pos,
84
- match
85
- });
86
- if (!tr) continue;
87
- dispatch?.(tr);
88
- if (rule.stop) return true;
89
- }
90
- return false;
91
- }
92
- const MAX_MATCH = 200;
93
-
94
- //#endregion
95
- export { defineTextBlockEnterRule as n, defineEnterRule as t };
96
- //# sourceMappingURL=enter-rule-D-p4ykfv.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enter-rule-D-p4ykfv.js","names":[],"sources":["../src/enter-rule/index.ts"],"sourcesContent":["import {\n defineFacet,\n defineFacetPayload,\n getNodeType,\n isTextSelection,\n maybeRun,\n OBJECT_REPLACEMENT_CHARACTER,\n pluginFacet,\n type PlainExtension,\n type PluginPayload,\n} from '@prosekit/core'\nimport { keydownHandler } from '@prosekit/pm/keymap'\nimport type { Attrs, NodeType } from '@prosekit/pm/model'\nimport { PluginKey, ProseMirrorPlugin, type Command, type EditorState, type Transaction } from '@prosekit/pm/state'\nimport type { EditorView } from '@prosekit/pm/view'\n\n/**\n * @public\n *\n * Options for {@link EnterRuleHandler}.\n */\nexport interface EnterRuleHandlerOptions {\n /**\n * The current editor state.\n */\n state: EditorState\n\n /**\n * The start position of the matched text.\n */\n from: number\n\n /**\n * The end position of the matched text.\n */\n to: number\n\n /**\n * The matched result from the regular expression.\n */\n match: RegExpExecArray\n}\n\n/**\n * @public\n */\nexport type EnterRuleHandler = (options: EnterRuleHandlerOptions) => Transaction | null\n\n/**\n * Options for {@link defineEnterRule}.\n *\n * @public\n */\nexport type EnterRuleOptions = {\n /**\n * The regular expression to match against. It should end with `$`.\n */\n regex: RegExp\n\n /**\n * A function to be called when an enter rule is triggered.\n */\n handler: EnterRuleHandler\n\n /**\n * Whether to stop further handlers from being called if this rule is triggered.\n *\n * @default false\n */\n stop?: boolean\n}\n\n/**\n * Options for {@link defineTextBlockEnterRule}.\n *\n * @public\n */\nexport interface TextBlockEnterRuleOptions {\n /**\n * The regular expression to match against. It should end with `$`.\n */\n regex: RegExp\n\n /**\n * The node type to replace the matched text with.\n */\n type: string | NodeType\n\n /**\n * Attributes to set on the node. If a function is provided, it will be called\n * with the matched result from the regular expression.\n */\n attrs?: Attrs | null | ((match: RegExpMatchArray) => Attrs | null)\n\n /**\n * Whether to stop further handlers from being called if this rule is triggered.\n *\n * @default true\n */\n stop?: boolean\n}\n\n/**\n * Defines an enter rule. An enter rule applies when the text directly in front of\n * the cursor matches `regex` and user presses Enter. The `regex` should end\n * with `$`.\n *\n * @param options\n *\n * @public\n */\nexport function defineEnterRule({\n regex,\n handler,\n stop = false,\n}: EnterRuleOptions): PlainExtension {\n const rule: EnterRule = new EnterRule(regex, handler, stop)\n return defineFacetPayload(enterRule, [rule]) as PlainExtension\n}\n\n/**\n * Defines an enter rule that replaces the matched text with a block node.\n *\n * See also {@link defineEnterRule}.\n *\n * @param options\n *\n * @public\n */\nexport function defineTextBlockEnterRule({\n regex,\n type,\n attrs,\n stop = true,\n}: TextBlockEnterRuleOptions): PlainExtension {\n return defineEnterRule({\n regex,\n handler: ({ state, from, to, match }) => {\n const nodeType = getNodeType(state.schema, type)\n const $start = state.doc.resolve(from)\n\n if (\n !$start\n .node(-1)\n .canReplaceWith($start.index(-1), $start.indexAfter(-1), nodeType)\n ) {\n return null\n }\n\n const nodeAttrs = maybeRun(attrs, match)\n return state.tr\n .delete(from, to)\n .setBlockType(from, from, nodeType, nodeAttrs)\n },\n stop,\n })\n}\n\n/**\n * @internal\n */\nclass EnterRule {\n constructor(\n readonly regex: RegExp,\n readonly handler: EnterRuleHandler,\n readonly stop: boolean,\n ) {}\n}\n\nconst enterRule = defineFacet<EnterRule, PluginPayload>({\n reduce: () => {\n let rules: EnterRule[] = []\n\n const command: Command = (state, dispatch, view) => {\n if (!view) return false\n return execRules(view, rules, dispatch)\n }\n const handler = keydownHandler({ Enter: command })\n const plugin = new ProseMirrorPlugin({\n key: new PluginKey('prosekit-enter-rule'),\n props: { handleKeyDown: handler },\n })\n\n return function reducer(inputs) {\n rules = inputs\n return plugin\n }\n },\n\n parent: pluginFacet,\n})\n\nfunction execRules(\n view: EditorView,\n rules: readonly EnterRule[],\n dispatch?: (tr: Transaction) => void,\n): boolean {\n if (view.composing) return false\n const state = view.state\n const selection = state.selection\n if (!isTextSelection(selection)) return false\n const $cursor = selection.$cursor\n if (!$cursor || $cursor.parent.type.spec.code) return false\n\n const textBefore = $cursor.parent.textBetween(\n Math.max(0, $cursor.parentOffset - MAX_MATCH),\n $cursor.parentOffset,\n null,\n OBJECT_REPLACEMENT_CHARACTER,\n )\n\n for (const rule of rules) {\n rule.regex.lastIndex = 0\n const match = rule.regex.exec(textBefore)\n const tr = match\n && rule.handler({\n state,\n from: $cursor.pos - match[0].length,\n to: $cursor.pos,\n match,\n })\n if (!tr) continue\n dispatch?.(tr)\n\n if (rule.stop) {\n return true\n }\n }\n return false\n}\n\nconst MAX_MATCH = 200\n"],"mappings":";;;;;;;;;;;;;;AA+GA,SAAgB,gBAAgB,EAC9B,OACA,SACA,OAAO,SAC4B;AAEnC,QAAO,mBAAmB,WAAW,CADb,IAAI,UAAU,OAAO,SAAS,KAAK,CAChB,CAAC;;;;;;;;;;;AAY9C,SAAgB,yBAAyB,EACvC,OACA,MACA,OACA,OAAO,QACqC;AAC5C,QAAO,gBAAgB;EACrB;EACA,UAAU,EAAE,OAAO,MAAM,IAAI,YAAY;GACvC,MAAM,WAAW,YAAY,MAAM,QAAQ,KAAK;GAChD,MAAM,SAAS,MAAM,IAAI,QAAQ,KAAK;AAEtC,OACE,CAAC,OACE,KAAK,GAAG,CACR,eAAe,OAAO,MAAM,GAAG,EAAE,OAAO,WAAW,GAAG,EAAE,SAAS,CAEpE,QAAO;GAGT,MAAM,YAAY,SAAS,OAAO,MAAM;AACxC,UAAO,MAAM,GACV,OAAO,MAAM,GAAG,CAChB,aAAa,MAAM,MAAM,UAAU,UAAU;;EAElD;EACD,CAAC;;;;;AAMJ,IAAM,YAAN,MAAgB;CACd,YACE,AAAS,OACT,AAAS,SACT,AAAS,MACT;EAHS;EACA;EACA;;;AAIb,MAAM,YAAY,YAAsC;CACtD,cAAc;EACZ,IAAI,QAAqB,EAAE;EAE3B,MAAM,WAAoB,OAAO,UAAU,SAAS;AAClD,OAAI,CAAC,KAAM,QAAO;AAClB,UAAO,UAAU,MAAM,OAAO,SAAS;;EAEzC,MAAM,UAAU,eAAe,EAAE,OAAO,SAAS,CAAC;EAClD,MAAM,SAAS,IAAI,kBAAkB;GACnC,KAAK,IAAI,UAAU,sBAAsB;GACzC,OAAO,EAAE,eAAe,SAAS;GAClC,CAAC;AAEF,SAAO,SAAS,QAAQ,QAAQ;AAC9B,WAAQ;AACR,UAAO;;;CAIX,QAAQ;CACT,CAAC;AAEF,SAAS,UACP,MACA,OACA,UACS;AACT,KAAI,KAAK,UAAW,QAAO;CAC3B,MAAM,QAAQ,KAAK;CACnB,MAAM,YAAY,MAAM;AACxB,KAAI,CAAC,gBAAgB,UAAU,CAAE,QAAO;CACxC,MAAM,UAAU,UAAU;AAC1B,KAAI,CAAC,WAAW,QAAQ,OAAO,KAAK,KAAK,KAAM,QAAO;CAEtD,MAAM,aAAa,QAAQ,OAAO,YAChC,KAAK,IAAI,GAAG,QAAQ,eAAe,UAAU,EAC7C,QAAQ,cACR,MACA,6BACD;AAED,MAAK,MAAM,QAAQ,OAAO;AACxB,OAAK,MAAM,YAAY;EACvB,MAAM,QAAQ,KAAK,MAAM,KAAK,WAAW;EACzC,MAAM,KAAK,SACN,KAAK,QAAQ;GACd;GACA,MAAM,QAAQ,MAAM,MAAM,GAAG;GAC7B,IAAI,QAAQ;GACZ;GACD,CAAC;AACJ,MAAI,CAAC,GAAI;AACT,aAAW,GAAG;AAEd,MAAI,KAAK,KACP,QAAO;;AAGX,QAAO;;AAGT,MAAM,YAAY"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-iLVR0eM0.js","names":["facet","getFiles"],"sources":["../src/file/helpers.ts","../src/file/file-drop-handler.ts","../src/file/file-paste-handler.ts","../src/file/file-upload.ts"],"sourcesContent":["import type { EditorView } from '@prosekit/pm/view'\n\ntype FileHandler<E extends Event> = (options: {\n view: EditorView\n event: E\n file: File\n}) => boolean | void\n\nfunction handleFile<E extends Event>(\n view: EditorView,\n event: E,\n file: File,\n handlers: FileHandler<E>[],\n) {\n // The last item in `handlers` should has the highest priority.\n for (let i = handlers.length - 1; i >= 0; i--) {\n const handler = handlers[i]\n if (handler({ view, event, file })) {\n return true\n }\n }\n return false\n}\n\nexport function handleEvent<E extends Event>(\n view: EditorView,\n event: E,\n handlers: FileHandler<E>[],\n getFiles: (event: E) => File[],\n): boolean {\n const files = getFiles(event)\n let handled = false\n for (const file of files) {\n if (handleFile(view, event, file, handlers)) {\n handled = true\n }\n }\n return handled\n}\n","import {\n defineFacet,\n defineFacetPayload,\n editorEventFacet,\n type DropHandler,\n type EditorEventPayload,\n type PlainExtension,\n} from '@prosekit/core'\nimport type { EditorView } from '@prosekit/pm/view'\n\nimport { handleEvent } from './helpers'\n\nexport interface FileDropHandlerOptions {\n /**\n * The editor view.\n */\n view: EditorView\n\n /**\n * The event that triggered the drop.\n */\n event: DragEvent\n\n /**\n * The file that was dropped.\n */\n file: File\n\n /**\n * The position of the document where the file was dropped.\n */\n pos: number\n}\n\n/**\n * A function that handles one of the files in a drop event.\n *\n * Returns `true` if the file was handled and thus should not be handled by\n * other handlers.\n */\nexport type FileDropHandler = (\n options: FileDropHandlerOptions,\n) => boolean | void\n\nexport function defineFileDropHandler(\n handler: FileDropHandler,\n): PlainExtension {\n return defineFacetPayload(facet, [handler]) as PlainExtension\n}\n\nfunction getFiles(event: DragEvent) {\n return Array.from(event.dataTransfer?.files ?? [])\n}\n\nconst facet = defineFacet<FileDropHandler, EditorEventPayload>({\n parent: editorEventFacet,\n singleton: true,\n reducer: (handlers: FileDropHandler[]): EditorEventPayload => {\n const dropHandler: DropHandler = (view, event): boolean => {\n const position = view.posAtCoords({ left: event.x, top: event.y })\n if (!position) {\n return false\n }\n const pos = position.inside > 0 ? position.inside : position.pos\n\n return handleEvent<DragEvent>(\n view,\n event,\n handlers.map((handler) => (options) => handler({ ...options, pos })),\n getFiles,\n )\n }\n return ['drop', dropHandler]\n },\n})\n","import {\n defineFacet,\n defineFacetPayload,\n editorEventFacet,\n type EditorEventPayload,\n type PasteHandler,\n type PlainExtension,\n} from '@prosekit/core'\nimport type { EditorView } from '@prosekit/pm/view'\n\nimport { handleEvent } from './helpers'\n\nexport interface FilePasteHandlerOptions {\n /**\n * The editor view.\n */\n view: EditorView\n\n /**\n * The event that triggered the paste.\n */\n event: ClipboardEvent\n\n /**\n * The file that was pasted.\n */\n file: File\n}\n\n/**\n * A function that handles one of the files in a paste event.\n *\n * Returns `true` if the file was handled and thus should not be handled by\n * other handlers.\n */\nexport type FilePasteHandler = (\n options: FilePasteHandlerOptions,\n) => boolean | void\n\nexport function defineFilePasteHandler(\n handler: FilePasteHandler,\n): PlainExtension {\n return defineFacetPayload(facet, [handler]) as PlainExtension\n}\n\nfunction getFiles(event: ClipboardEvent) {\n return Array.from(event.clipboardData?.files ?? [])\n}\n\nconst facet = defineFacet<FilePasteHandler, EditorEventPayload>({\n parent: editorEventFacet,\n singleton: true,\n reducer: (handlers: FilePasteHandler[]): EditorEventPayload => {\n const pasteHandler: PasteHandler = (view, event): boolean => {\n return handleEvent<ClipboardEvent>(view, event, handlers, getFiles)\n }\n return ['paste', pasteHandler]\n },\n})\n","import { ProseKitError } from '@prosekit/core'\n\n/**\n * An interface representing the upload progress.\n */\nexport interface UploadProgress {\n // A number representing the amount of work already performed by the\n // underlying process.\n loaded: number\n // A number representing the total amount of work that the underlying\n // process is in the progress of performing.\n total: number\n}\n\nexport interface UploaderOptions {\n /**\n * The file to be uploaded.\n */\n file: File\n\n /**\n * A callback function that should be called with the upload progress updates.\n */\n onProgress: (progress: UploadProgress) => void\n}\n\n/**\n * The implementation of the actual upload function. You need to implement this\n * function to upload files to your desired destination.\n */\nexport type Uploader<Result> = (options: UploaderOptions) => Promise<Result>\n\n/**\n * A class that represents a upload task.\n */\nexport class UploadTask<Result> {\n /**\n * An [object URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL)\n * representing the file to be uploaded. This URL will be revoked once the\n * upload is complete successfully.\n */\n readonly objectURL: string\n\n /**\n * A boolean indicating whether the upload is complete (either successfully or with an error).\n */\n protected done = false\n\n /**\n * If the upload is complete successfully, this will be the result of the upload.\n */\n protected result: Result | undefined\n\n /**\n * If the upload is complete with an error, this will be the error that occurred.\n */\n protected error: Error | undefined\n\n /**\n * A promise that fulfills once the upload is complete, or rejects if an error occurs.\n */\n readonly finished: Promise<Result>\n\n private subscribers: ((progress: UploadProgress) => void)[] = []\n\n /**\n * Creates a new upload task. You can find the upload task by its object URL\n * later using `UploadTask.get()`.\n *\n * @param options - The options for the upload task.\n */\n constructor({ file, uploader }: { file: File; uploader: Uploader<Result> }) {\n this.objectURL = URL.createObjectURL(file)\n this.finished = new Promise((resolve, reject) => {\n const maybePromise = uploader({\n file,\n onProgress: (progress) => {\n for (const subscriber of this.subscribers) {\n subscriber(progress)\n }\n },\n })\n Promise.resolve(maybePromise).then(\n (result) => {\n this.done = true\n URL.revokeObjectURL(this.objectURL)\n this.result = result\n resolve(result)\n },\n (err) => {\n this.done = true\n const error = new ProseKitError('[prosekit] Failed to upload file', { cause: err })\n this.error = error\n reject(error)\n },\n )\n })\n store.set(this.objectURL, this)\n }\n\n /**\n * Subscribes to progress updates. Returns a function to unsubscribe.\n */\n public subscribeProgress(\n callback: (progress: UploadProgress) => void,\n ): VoidFunction {\n this.subscribers.push(callback)\n return () => {\n this.subscribers = this.subscribers.filter(\n (subscriber) => subscriber !== callback,\n )\n }\n }\n\n /**\n * Finds an upload task from the global store by its object URL.\n */\n static get<Result = unknown>(\n objectURL: string,\n ): UploadTask<Result> | undefined {\n return store.get(objectURL) as UploadTask<Result> | undefined\n }\n\n /**\n * Deletes an upload task from the global store by its object URL.\n */\n static delete(objectURL: string): void {\n store.delete(objectURL)\n }\n}\n\nconst store = new Map<string, UploadTask<unknown>>()\n"],"mappings":";;;AAQA,SAAS,WACP,MACA,OACA,MACA,UACA;AAEA,MAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,MAAM,UAAU,SAAS;AACzB,MAAI,QAAQ;GAAE;GAAM;GAAO;GAAM,CAAC,CAChC,QAAO;;AAGX,QAAO;;AAGT,SAAgB,YACd,MACA,OACA,UACA,UACS;CACT,MAAM,QAAQ,SAAS,MAAM;CAC7B,IAAI,UAAU;AACd,MAAK,MAAM,QAAQ,MACjB,KAAI,WAAW,MAAM,OAAO,MAAM,SAAS,CACzC,WAAU;AAGd,QAAO;;;;;ACOT,SAAgB,sBACd,SACgB;AAChB,QAAO,mBAAmBA,SAAO,CAAC,QAAQ,CAAC;;AAG7C,SAASC,WAAS,OAAkB;AAClC,QAAO,MAAM,KAAK,MAAM,cAAc,SAAS,EAAE,CAAC;;AAGpD,MAAMD,UAAQ,YAAiD;CAC7D,QAAQ;CACR,WAAW;CACX,UAAU,aAAoD;EAC5D,MAAM,eAA4B,MAAM,UAAmB;GACzD,MAAM,WAAW,KAAK,YAAY;IAAE,MAAM,MAAM;IAAG,KAAK,MAAM;IAAG,CAAC;AAClE,OAAI,CAAC,SACH,QAAO;GAET,MAAM,MAAM,SAAS,SAAS,IAAI,SAAS,SAAS,SAAS;AAE7D,UAAO,YACL,MACA,OACA,SAAS,KAAK,aAAa,YAAY,QAAQ;IAAE,GAAG;IAAS;IAAK,CAAC,CAAC,EACpEC,WACD;;AAEH,SAAO,CAAC,QAAQ,YAAY;;CAE/B,CAAC;;;;ACnCF,SAAgB,uBACd,SACgB;AAChB,QAAO,mBAAmB,OAAO,CAAC,QAAQ,CAAC;;AAG7C,SAAS,SAAS,OAAuB;AACvC,QAAO,MAAM,KAAK,MAAM,eAAe,SAAS,EAAE,CAAC;;AAGrD,MAAM,QAAQ,YAAkD;CAC9D,QAAQ;CACR,WAAW;CACX,UAAU,aAAqD;EAC7D,MAAM,gBAA8B,MAAM,UAAmB;AAC3D,UAAO,YAA4B,MAAM,OAAO,UAAU,SAAS;;AAErE,SAAO,CAAC,SAAS,aAAa;;CAEjC,CAAC;;;;;;;ACvBF,IAAa,aAAb,MAAgC;;;;;;;CAoC9B,YAAY,EAAE,MAAM,YAAwD;cAzB3D;qBAiB6C,EAAE;AAS9D,OAAK,YAAY,IAAI,gBAAgB,KAAK;AAC1C,OAAK,WAAW,IAAI,SAAS,SAAS,WAAW;GAC/C,MAAM,eAAe,SAAS;IAC5B;IACA,aAAa,aAAa;AACxB,UAAK,MAAM,cAAc,KAAK,YAC5B,YAAW,SAAS;;IAGzB,CAAC;AACF,WAAQ,QAAQ,aAAa,CAAC,MAC3B,WAAW;AACV,SAAK,OAAO;AACZ,QAAI,gBAAgB,KAAK,UAAU;AACnC,SAAK,SAAS;AACd,YAAQ,OAAO;OAEhB,QAAQ;AACP,SAAK,OAAO;IACZ,MAAM,QAAQ,IAAI,cAAc,oCAAoC,EAAE,OAAO,KAAK,CAAC;AACnF,SAAK,QAAQ;AACb,WAAO,MAAM;KAEhB;IACD;AACF,QAAM,IAAI,KAAK,WAAW,KAAK;;;;;CAMjC,AAAO,kBACL,UACc;AACd,OAAK,YAAY,KAAK,SAAS;AAC/B,eAAa;AACX,QAAK,cAAc,KAAK,YAAY,QACjC,eAAe,eAAe,SAChC;;;;;;CAOL,OAAO,IACL,WACgC;AAChC,SAAO,MAAM,IAAI,UAAU;;;;;CAM7B,OAAO,OAAO,WAAyB;AACrC,QAAM,OAAO,UAAU;;;AAI3B,MAAM,wBAAQ,IAAI,KAAkC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-cp1u4e0e.d.ts","names":[],"sources":["../src/file/file-drop-handler.ts","../src/file/file-paste-handler.ts","../src/file/file-upload.ts"],"mappings":";;;;UAYiB,sBAAA;;AAAjB;;EAIE,IAAA,EAAM,UAAA;EAAA;;;EAKN,KAAA,EAAO,SAAA;EAKG;;;EAAV,IAAA,EAAM,IAAA;EALC;;;EAUP,GAAA;AAAA;;AASF;;;;;KAAY,eAAA,IACV,OAAA,EAAS,sBAAA;AAAA,iBAGK,qBAAA,CACd,OAAA,EAAS,eAAA,GACR,cAAA;;;UClCc,uBAAA;;ADAjB;;ECIE,IAAA,EAAM,UAAA;EDAA;;;ECKN,KAAA,EAAO,cAAA;EDKG;;;ECAV,IAAA,EAAM,IAAA;AAAA;;;;;;ADcR;KCLY,gBAAA,IACV,OAAA,EAAS,uBAAA;AAAA,iBAGK,sBAAA,CACd,OAAA,EAAS,gBAAA,GACR,cAAA;;;;;;UCpCc,cAAA;EAGf,MAAA;EAGA,KAAA;AAAA;AAAA,UAGe,eAAA;EFOR;;;EEHP,IAAA,EAAM,IAAA;EFFN;;;EEOA,UAAA,GAAa,QAAA,EAAU,cAAA;AAAA;;;;;KAOb,QAAA,YAAoB,OAAA,EAAS,eAAA,KAAoB,OAAA,CAAQ,MAAA;;;;cAKxD,UAAA;EFSG;;;;;EAAA,SEHL,SAAA;EFKR;;;EAAA,UEAS,IAAA;;;ADlCZ;YCuCY,MAAA,EAAQ,MAAA;;;;YAKR,KAAA,EAAO,KAAA;ED9BP;;;EAAA,SCmCD,QAAA,EAAU,OAAA,CAAQ,MAAA;EAAA,QAEnB,WAAA;ED1CD;;;;;AAcT;;ICoCgB,IAAA;IAAM;EAAA;IAAc,IAAA,EAAM,IAAA;IAAM,QAAA,EAAU,QAAA,CAAS,MAAA;EAAA;EDhCnD;;;ECgEP,iBAAA,CACL,QAAA,GAAW,QAAA,EAAU,cAAA,YACpB,YAAA;EDjEM;;;EAAA,OC6EF,GAAA,kBAAA,CACL,SAAA,WACC,UAAA,CAAW,MAAA;ED9EC;;;EAAA,OCqFR,MAAA,CAAO,SAAA;AAAA"}