@milkdown/plugin-slash 6.5.2 → 6.5.3

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/src/config.ts CHANGED
@@ -1,137 +1,142 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { commandsCtx, Ctx, schemaCtx, themeManagerCtx } from '@milkdown/core';
3
- import { Node } from '@milkdown/prose/model';
4
- import { EditorState } from '@milkdown/prose/state';
2
+ import type { Ctx } from '@milkdown/core'
3
+ import { commandsCtx, editorViewCtx, schemaCtx, themeManagerCtx } from '@milkdown/core'
4
+ import type { Node } from '@milkdown/prose/model'
5
+ import type { EditorState } from '@milkdown/prose/state'
5
6
 
6
- import { WrappedAction } from './item';
7
- import { createDropdownItem } from './utility';
7
+ import type { WrappedAction } from './item'
8
+ import { createDropdownItem } from './utility'
8
9
 
9
- type Nullable<T> = T | null | undefined;
10
+ type Nullable<T> = T | null | undefined
10
11
 
11
- export type StatusConfig = {
12
- placeholder?: Nullable<string>;
13
- actions?: Nullable<WrappedAction[]>;
14
- };
12
+ export interface StatusConfig {
13
+ placeholder?: Nullable<string>
14
+ actions?: Nullable<WrappedAction[]>
15
+ }
15
16
 
16
- export type StatusConfigBuilderParams = {
17
- content: string;
18
- isTopLevel: boolean;
19
- parentNode: Node;
20
- state: EditorState;
21
- };
17
+ export interface StatusConfigBuilderParams {
18
+ content: string
19
+ isTopLevel: boolean
20
+ parentNode: Node
21
+ state: EditorState
22
+ }
22
23
 
23
- export type StatusConfigBuilder = (params: StatusConfigBuilderParams) => Nullable<StatusConfig>;
24
+ export type StatusConfigBuilder = (params: StatusConfigBuilderParams) => Nullable<StatusConfig>
24
25
 
25
- export type Config = (ctx: Ctx) => StatusConfigBuilder;
26
+ export type Config = (ctx: Ctx) => StatusConfigBuilder
26
27
 
27
28
  export const defaultActions = (ctx: Ctx, input = '/'): WrappedAction[] => {
28
- const { nodes } = ctx.get(schemaCtx);
29
- const actions: Array<WrappedAction & { keyword: string[]; typeName: string }> = [
30
- {
31
- id: 'h1',
32
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Large Heading', 'h1'),
33
- command: () => ctx.get(commandsCtx).call('TurnIntoHeading', 1),
34
- keyword: ['h1', 'large heading'],
35
- typeName: 'heading',
36
- },
37
- {
38
- id: 'h2',
39
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Medium Heading', 'h2'),
40
- command: () => ctx.get(commandsCtx).call('TurnIntoHeading', 2),
41
- keyword: ['h2', 'medium heading'],
42
- typeName: 'heading',
43
- },
44
- {
45
- id: 'h3',
46
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Small Heading', 'h3'),
47
- command: () => ctx.get(commandsCtx).call('TurnIntoHeading', 3),
48
- keyword: ['h3', 'small heading'],
49
- typeName: 'heading',
50
- },
51
- {
52
- id: 'bulletList',
53
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Bullet List', 'bulletList'),
54
- command: () => ctx.get(commandsCtx).call('WrapInBulletList'),
55
- keyword: ['bullet list', 'ul'],
56
- typeName: 'bullet_list',
57
- },
58
- {
59
- id: 'orderedList',
60
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Ordered List', 'orderedList'),
61
- command: () => ctx.get(commandsCtx).call('WrapInOrderedList'),
62
- keyword: ['ordered list', 'ol'],
63
- typeName: 'ordered_list',
64
- },
65
- {
66
- id: 'taskList',
67
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Task List', 'taskList'),
68
- command: () => ctx.get(commandsCtx).call('TurnIntoTaskList'),
69
- keyword: ['task list', 'task'],
70
- typeName: 'task_list_item',
71
- },
72
- {
73
- id: 'image',
74
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Image', 'image'),
75
- command: () => ctx.get(commandsCtx).call('InsertImage'),
76
- keyword: ['image'],
77
- typeName: 'image',
78
- },
79
- {
80
- id: 'blockquote',
81
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Quote', 'quote'),
82
- command: () => ctx.get(commandsCtx).call('WrapInBlockquote'),
83
- keyword: ['quote', 'blockquote'],
84
- typeName: 'blockquote',
85
- },
86
- {
87
- id: 'table',
88
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Table', 'table'),
89
- command: () => ctx.get(commandsCtx).call('InsertTable'),
90
- keyword: ['table'],
91
- typeName: 'table',
92
- },
93
- {
94
- id: 'code',
95
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Code Fence', 'code'),
96
- command: () => ctx.get(commandsCtx).call('TurnIntoCodeFence'),
97
- keyword: ['code'],
98
- typeName: 'fence',
99
- },
100
- {
101
- id: 'divider',
102
- dom: createDropdownItem(ctx.get(themeManagerCtx), 'Divide Line', 'divider'),
103
- command: () => ctx.get(commandsCtx).call('InsertHr'),
104
- keyword: ['divider', 'hr'],
105
- typeName: 'hr',
106
- },
107
- ];
29
+ const { nodes } = ctx.get(schemaCtx)
30
+ const actions: Array<WrappedAction & { keyword: string[]; typeName: string }> = [
31
+ {
32
+ id: 'h1',
33
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Large Heading', 'h1'),
34
+ command: () => ctx.get(commandsCtx).call('TurnIntoHeading', 1),
35
+ keyword: ['h1', 'large heading'],
36
+ typeName: 'heading',
37
+ },
38
+ {
39
+ id: 'h2',
40
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Medium Heading', 'h2'),
41
+ command: () => ctx.get(commandsCtx).call('TurnIntoHeading', 2),
42
+ keyword: ['h2', 'medium heading'],
43
+ typeName: 'heading',
44
+ },
45
+ {
46
+ id: 'h3',
47
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Small Heading', 'h3'),
48
+ command: () => ctx.get(commandsCtx).call('TurnIntoHeading', 3),
49
+ keyword: ['h3', 'small heading'],
50
+ typeName: 'heading',
51
+ },
52
+ {
53
+ id: 'bulletList',
54
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Bullet List', 'bulletList'),
55
+ command: () => ctx.get(commandsCtx).call('WrapInBulletList'),
56
+ keyword: ['bullet list', 'ul'],
57
+ typeName: 'bullet_list',
58
+ },
59
+ {
60
+ id: 'orderedList',
61
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Ordered List', 'orderedList'),
62
+ command: () => ctx.get(commandsCtx).call('WrapInOrderedList'),
63
+ keyword: ['ordered list', 'ol'],
64
+ typeName: 'ordered_list',
65
+ },
66
+ {
67
+ id: 'taskList',
68
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Task List', 'taskList'),
69
+ command: () => ctx.get(commandsCtx).call('TurnIntoTaskList'),
70
+ keyword: ['task list', 'task'],
71
+ typeName: 'task_list_item',
72
+ },
73
+ {
74
+ id: 'image',
75
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Image', 'image'),
76
+ command: () => ctx.get(commandsCtx).call('InsertImage'),
77
+ keyword: ['image'],
78
+ typeName: 'image',
79
+ },
80
+ {
81
+ id: 'blockquote',
82
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Quote', 'quote'),
83
+ command: () => ctx.get(commandsCtx).call('WrapInBlockquote'),
84
+ keyword: ['quote', 'blockquote'],
85
+ typeName: 'blockquote',
86
+ },
87
+ {
88
+ id: 'table',
89
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Table', 'table'),
90
+ command: () => ctx.get(commandsCtx).call('InsertTable'),
91
+ keyword: ['table'],
92
+ typeName: 'table',
93
+ },
94
+ {
95
+ id: 'code',
96
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Code Fence', 'code'),
97
+ command: () => ctx.get(commandsCtx).call('TurnIntoCodeFence'),
98
+ keyword: ['code'],
99
+ typeName: 'fence',
100
+ },
101
+ {
102
+ id: 'divider',
103
+ dom: createDropdownItem(ctx.get(themeManagerCtx), 'Divide Line', 'divider'),
104
+ command: () => ctx.get(commandsCtx).call('InsertHr'),
105
+ keyword: ['divider', 'hr'],
106
+ typeName: 'hr',
107
+ },
108
+ ]
108
109
 
109
- const userInput = input.slice(1).toLocaleLowerCase();
110
+ const userInput = input.slice(1).toLocaleLowerCase()
110
111
 
111
- return actions
112
- .filter((action) => !!nodes[action.typeName] && action.keyword.some((keyword) => keyword.includes(userInput)))
113
- .map(({ keyword, typeName, ...action }) => action);
114
- };
112
+ return actions
113
+ .filter(action => !!nodes[action.typeName] && action.keyword.some(keyword => keyword.includes(userInput)))
114
+ .map(({ keyword, typeName, ...action }) => action)
115
+ }
115
116
 
116
117
  export const defaultConfig: Config = (ctx) => {
117
- return ({ content, isTopLevel }) => {
118
- if (!isTopLevel) return null;
118
+ return ({ content, isTopLevel }) => {
119
+ if (!isTopLevel)
120
+ return null
119
121
 
120
- if (!content) {
121
- return { placeholder: 'Type / to use the slash commands...' };
122
- }
122
+ const view = ctx.get(editorViewCtx)
123
+ if (!view?.editable)
124
+ return null
123
125
 
124
- if (content.startsWith('/')) {
125
- return content === '/'
126
- ? {
127
- placeholder: 'Type to filter...',
128
- actions: defaultActions(ctx),
129
- }
130
- : {
131
- actions: defaultActions(ctx, content),
132
- };
133
- }
126
+ if (!content)
127
+ return { placeholder: 'Type / to use the slash commands...' }
134
128
 
135
- return null;
136
- };
137
- };
129
+ if (content.startsWith('/')) {
130
+ return content === '/'
131
+ ? {
132
+ placeholder: 'Type to filter...',
133
+ actions: defaultActions(ctx),
134
+ }
135
+ : {
136
+ actions: defaultActions(ctx, content),
137
+ }
138
+ }
139
+
140
+ return null
141
+ }
142
+ }
package/src/index.ts CHANGED
@@ -1,34 +1,35 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { AtomList, createPlugin } from '@milkdown/utils';
2
+ import { AtomList, createPlugin } from '@milkdown/utils'
3
3
 
4
- import type { Config } from './config';
5
- import { defaultConfig } from './config';
6
- import { createSlashPlugin } from './prose-plugin';
7
- import { CalcPosition, defaultCalcPosition } from './prose-plugin/view';
4
+ import type { Config } from './config'
5
+ import { defaultConfig } from './config'
6
+ import { createSlashPlugin } from './prose-plugin'
7
+ import type { CalcPosition } from './prose-plugin/view'
8
+ import { defaultCalcPosition } from './prose-plugin/view'
8
9
 
9
- export type { Config, StatusConfig, StatusConfigBuilder, StatusConfigBuilderParams } from './config';
10
- export { defaultActions, defaultConfig } from './config';
11
- export type { Action, WrappedAction } from './item';
12
- export { createDropdownItem } from './utility';
10
+ export type { Config, StatusConfig, StatusConfigBuilder, StatusConfigBuilderParams } from './config'
11
+ export { defaultActions, defaultConfig } from './config'
12
+ export type { Action, WrappedAction } from './item'
13
+ export { createDropdownItem } from './utility'
13
14
 
14
- export type Options = {
15
- config: Config;
16
- calcPosition: CalcPosition;
17
- };
15
+ export interface Options {
16
+ config: Config
17
+ calcPosition: CalcPosition
18
+ }
18
19
 
19
20
  export const slashPlugin = createPlugin<string, Options>((utils, options) => {
20
- const slashConfig = options?.config ?? defaultConfig;
21
- const calcPosition = options?.calcPosition ?? defaultCalcPosition;
21
+ const slashConfig = options?.config ?? defaultConfig
22
+ const calcPosition = options?.calcPosition ?? defaultCalcPosition
22
23
 
23
- return {
24
- prosePlugins: (_, ctx) => {
25
- const config = slashConfig(ctx);
24
+ return {
25
+ prosePlugins: (_, ctx) => {
26
+ const config = slashConfig(ctx)
26
27
 
27
- const plugin = createSlashPlugin(utils, config, 'slash-dropdown', calcPosition);
28
+ const plugin = createSlashPlugin(utils, config, 'slash-dropdown', calcPosition)
28
29
 
29
- return [plugin];
30
- },
31
- };
32
- });
30
+ return [plugin]
31
+ },
32
+ }
33
+ })
33
34
 
34
- export const slash = AtomList.create([slashPlugin()]);
35
+ export const slash = AtomList.create([slashPlugin()])
package/src/item.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import type { Command } from '@milkdown/prose/state';
2
+ import type { Command } from '@milkdown/prose/state'
3
3
 
4
- import { cleanUpAndCreateNode } from './utility';
4
+ import { cleanUpAndCreateNode } from './utility'
5
5
 
6
- export type Action = {
7
- id: string;
8
- $: HTMLElement;
9
- command: Command;
10
- };
6
+ export interface Action {
7
+ id: string
8
+ $: HTMLElement
9
+ command: Command
10
+ }
11
11
 
12
12
  export type WrappedAction = Pick<Action, 'id'> & {
13
- command: () => void;
14
- dom: HTMLElement;
15
- };
13
+ command: () => void
14
+ dom: HTMLElement
15
+ }
16
16
 
17
17
  export const transformAction = (action: WrappedAction): Action => ({
18
- id: action.id,
19
- $: action.dom,
20
- command: cleanUpAndCreateNode(action.command),
21
- });
18
+ id: action.id,
19
+ $: action.dom,
20
+ command: cleanUpAndCreateNode(action.command),
21
+ })
@@ -1,51 +1,50 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import scrollIntoView from 'smooth-scroll-into-view-if-needed';
2
+ import scrollIntoView from 'smooth-scroll-into-view-if-needed'
3
3
 
4
- import { Status } from './status';
4
+ import type { Status } from './status'
5
5
 
6
- type Listeners = {
7
- mouseEnter: EventListener;
8
- mouseLeave: EventListener;
9
- };
6
+ interface Listeners {
7
+ mouseEnter: EventListener
8
+ mouseLeave: EventListener
9
+ }
10
10
 
11
11
  export const renderDropdown = (status: Status, dropdownElement: HTMLElement, listeners: Listeners): boolean => {
12
- const { actions } = status.get();
13
-
14
- if (!actions.length) {
15
- dropdownElement.classList.add('hide');
16
- return false;
17
- }
18
-
19
- dropdownElement.childNodes.forEach((child) => {
20
- child.removeEventListener('mouseenter', listeners.mouseEnter);
21
- child.removeEventListener('mouseleave', listeners.mouseLeave);
22
- });
23
-
24
- while (dropdownElement.firstChild) {
25
- dropdownElement.firstChild.remove();
26
- }
27
-
28
- actions.forEach(({ $ }) => {
29
- $.classList.remove('active');
30
- $.addEventListener('mouseenter', listeners.mouseEnter);
31
- $.addEventListener('mouseleave', listeners.mouseLeave);
32
- dropdownElement.appendChild($);
33
- });
34
-
35
- dropdownElement.style.maxHeight = '';
36
- dropdownElement.classList.remove('hide');
37
-
38
- const first$ = actions[0];
39
- if (first$) {
40
- first$.$.classList.add('active');
41
- requestAnimationFrame(() => {
42
- scrollIntoView(first$.$, {
43
- scrollMode: 'if-needed',
44
- block: 'nearest',
45
- inline: 'nearest',
46
- });
47
- });
48
- }
49
-
50
- return true;
51
- };
12
+ const { actions } = status.get()
13
+
14
+ if (!actions.length) {
15
+ dropdownElement.classList.add('hide')
16
+ return false
17
+ }
18
+
19
+ dropdownElement.childNodes.forEach((child) => {
20
+ child.removeEventListener('mouseenter', listeners.mouseEnter)
21
+ child.removeEventListener('mouseleave', listeners.mouseLeave)
22
+ })
23
+
24
+ while (dropdownElement.firstChild)
25
+ dropdownElement.firstChild.remove()
26
+
27
+ actions.forEach(({ $ }) => {
28
+ $.classList.remove('active')
29
+ $.addEventListener('mouseenter', listeners.mouseEnter)
30
+ $.addEventListener('mouseleave', listeners.mouseLeave)
31
+ dropdownElement.appendChild($)
32
+ })
33
+
34
+ dropdownElement.style.maxHeight = ''
35
+ dropdownElement.classList.remove('hide')
36
+
37
+ const first$ = actions[0]
38
+ if (first$) {
39
+ first$.$.classList.add('active')
40
+ requestAnimationFrame(() => {
41
+ scrollIntoView(first$.$, {
42
+ scrollMode: 'if-needed',
43
+ block: 'nearest',
44
+ inline: 'nearest',
45
+ })
46
+ })
47
+ }
48
+
49
+ return true
50
+ }
@@ -1,25 +1,26 @@
1
1
  /* Copyright 2021, Milkdown by Mirone. */
2
- import { Plugin, PluginKey } from '@milkdown/prose/state';
3
- import { ThemeUtils } from '@milkdown/utils';
2
+ import { Plugin, PluginKey } from '@milkdown/prose/state'
3
+ import type { ThemeUtils } from '@milkdown/utils'
4
4
 
5
- import type { StatusConfigBuilder } from '..';
6
- import { createProps } from './props';
7
- import { createStatus } from './status';
8
- import { CalcPosition, createView } from './view';
5
+ import type { StatusConfigBuilder } from '..'
6
+ import { createProps } from './props'
7
+ import { createStatus } from './status'
8
+ import type { CalcPosition } from './view'
9
+ import { createView } from './view'
9
10
 
10
- export const key = 'MILKDOWN_SLASH';
11
+ export const key = 'MILKDOWN_SLASH'
11
12
 
12
13
  export const createSlashPlugin = (
13
- utils: ThemeUtils,
14
- builder: StatusConfigBuilder,
15
- className: string,
16
- calcPosition: CalcPosition,
14
+ utils: ThemeUtils,
15
+ builder: StatusConfigBuilder,
16
+ className: string,
17
+ calcPosition: CalcPosition,
17
18
  ) => {
18
- const status = createStatus(builder);
19
+ const status = createStatus(builder)
19
20
 
20
- return new Plugin({
21
- key: new PluginKey(key),
22
- props: createProps(status, utils),
23
- view: (view) => createView(status, view, utils, className, calcPosition),
24
- });
25
- };
21
+ return new Plugin({
22
+ key: new PluginKey(key),
23
+ props: createProps(status, utils),
24
+ view: view => createView(status, view, utils, className, calcPosition),
25
+ })
26
+ }