@use-kona/editor 0.1.17 → 0.1.18

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.
@@ -23,7 +23,6 @@ const Menu = (props)=>{
23
23
  match: (n)=>Editor.isBlock(editor, n)
24
24
  });
25
25
  const isBrowseMode = 'string' == typeof store.filter && '' === store.filter;
26
- const isSearchMode = 'string' == typeof store.filter && '' !== store.filter;
27
26
  const { commands, isLoading, isError } = useResolvedCommands({
28
27
  rootCommands,
29
28
  filter: store.filter,
@@ -67,9 +66,8 @@ const Menu = (props)=>{
67
66
  store.openId
68
67
  ]);
69
68
  useEffect(()=>{
70
- if (false === store.filter || isSearchMode) setActive(0);
69
+ if (false === store.filter || 'string' == typeof store.filter && '' !== store.filter) setActive(0);
71
70
  }, [
72
- isSearchMode,
73
71
  store.filter
74
72
  ]);
75
73
  useEffect(()=>{
@@ -199,7 +197,6 @@ const Menu = (props)=>{
199
197
  const hasRows = entries.length > 0 || isLoading || isError;
200
198
  if (false === store.filter || !hasRows) return null;
201
199
  if (entry && ignoreNodes.includes(entry[0].type)) return null;
202
- const pathLabel = path.map((item)=>item.title).join(' / ');
203
200
  return /*#__PURE__*/ createPortal(renderMenu(/*#__PURE__*/ jsxs(Fragment, {
204
201
  children: [
205
202
  store.isOpen && /*#__PURE__*/ jsx("div", {
@@ -216,10 +213,6 @@ const Menu = (props)=>{
216
213
  event.preventDefault();
217
214
  },
218
215
  children: [
219
- isBrowseMode && pathLabel && /*#__PURE__*/ jsx("div", {
220
- className: styles_module.path,
221
- children: pathLabel
222
- }),
223
216
  entries.map((entry, index)=>{
224
217
  if ('back' === entry.type) return /*#__PURE__*/ jsxs("button", {
225
218
  type: "button",
@@ -271,17 +264,11 @@ const Menu = (props)=>{
271
264
  className: styles_module.icon,
272
265
  children: entry.command.command.icon
273
266
  }),
274
- /*#__PURE__*/ jsxs("span", {
267
+ /*#__PURE__*/ jsx("span", {
275
268
  className: styles_module.content,
276
- children: [
277
- /*#__PURE__*/ jsx("span", {
278
- children: entry.command.command.title
279
- }),
280
- isSearchMode && entry.command.breadcrumb && /*#__PURE__*/ jsx("span", {
281
- className: styles_module.breadcrumb,
282
- children: entry.command.breadcrumb
283
- })
284
- ]
269
+ children: /*#__PURE__*/ jsx("span", {
270
+ children: entry.command.command.title
271
+ })
285
272
  }),
286
273
  entry.command.isSubmenu && isBrowseMode && /*#__PURE__*/ jsx("span", {
287
274
  className: styles_module.submenu,
@@ -4,7 +4,6 @@ export type ResolvedCommand = {
4
4
  command: Command;
5
5
  key: string;
6
6
  path: CommandPathEntry[];
7
- breadcrumb: string;
8
7
  isSubmenu: boolean;
9
8
  };
10
9
  export type ResolveCommandsParams = {
@@ -18,17 +18,21 @@ const toResolvedCommand = (command, parentPath)=>{
18
18
  command,
19
19
  path,
20
20
  key: pathToKey(path),
21
- breadcrumb: parentPath.map((item)=>item.title).join(' / '),
22
21
  isSubmenu: Boolean(command.getCommands)
23
22
  };
24
23
  };
25
- const resolveBrowseCommands = async (params, resolveChildCommands)=>{
24
+ const resolveCurrentLevelCommands = async (params, resolveChildCommands, queryForCurrentLevel)=>{
26
25
  const { rootCommands, path, editor } = params;
27
26
  let currentCommands = rootCommands;
28
27
  let currentPath = [];
29
- for (const item of path){
28
+ for(let index = 0; index < path.length; index++){
29
+ const item = path[index];
30
+ const isLastPathItem = index === path.length - 1;
30
31
  const command = currentCommands.find((entry)=>entry.name === item.name);
31
- if (!command?.getCommands) return [];
32
+ if (!command?.getCommands) return {
33
+ commands: [],
34
+ path: currentPath
35
+ };
32
36
  currentPath = [
33
37
  ...currentPath,
34
38
  toPathEntry(command)
@@ -36,37 +40,24 @@ const resolveBrowseCommands = async (params, resolveChildCommands)=>{
36
40
  currentCommands = await resolveChildCommands({
37
41
  command,
38
42
  path: currentPath,
39
- query: '',
43
+ query: isLastPathItem ? queryForCurrentLevel : '',
40
44
  editor
41
45
  });
42
46
  }
43
- return currentCommands.map((command)=>toResolvedCommand(command, currentPath));
47
+ return {
48
+ commands: currentCommands,
49
+ path: currentPath
50
+ };
51
+ };
52
+ const resolveBrowseCommands = async (params, resolveChildCommands)=>{
53
+ const currentLevel = await resolveCurrentLevelCommands(params, resolveChildCommands, '');
54
+ return currentLevel.commands.map((command)=>toResolvedCommand(command, currentLevel.path));
44
55
  };
45
56
  const resolveSearchCommands = async (params, resolveChildCommands)=>{
46
- const { rootCommands, filter, editor } = params;
47
- const commands = [];
48
- const walk = async (levelCommands, parentPath)=>{
49
- for (const command of levelCommands){
50
- if (command.getCommands) {
51
- if (isCommandMatchesQuery(command, filter)) commands.push(toResolvedCommand(command, parentPath));
52
- const currentPath = [
53
- ...parentPath,
54
- toPathEntry(command)
55
- ];
56
- const children = await resolveChildCommands({
57
- command,
58
- path: currentPath,
59
- query: filter,
60
- editor
61
- });
62
- await walk(children, currentPath);
63
- continue;
64
- }
65
- if (command.action && isCommandMatchesQuery(command, filter)) commands.push(toResolvedCommand(command, parentPath));
66
- }
67
- };
68
- await walk(rootCommands, []);
69
- return commands;
57
+ const { filter } = params;
58
+ const currentLevel = await resolveCurrentLevelCommands(params, resolveChildCommands, filter);
59
+ const matchedCommands = currentLevel.commands.filter((command)=>isCommandMatchesQuery(command, filter));
60
+ return matchedCommands.map((command)=>toResolvedCommand(command, currentLevel.path));
70
61
  };
71
62
  class CommandsResolver {
72
63
  cache = new Map();
@@ -110,7 +110,7 @@ describe('CommandsResolver', ()=>{
110
110
  expect(result.commands).toHaveLength(1);
111
111
  expect(result.commands[0]?.command.name).toBe('code');
112
112
  });
113
- it('returns global leaf query matches with breadcrumbs', async ()=>{
113
+ it('searches only root level when path is empty', async ()=>{
114
114
  const resolver = new CommandsResolver();
115
115
  const rootCommands = [
116
116
  {
@@ -120,14 +120,37 @@ describe('CommandsResolver', ()=>{
120
120
  icon: null,
121
121
  getCommands: ()=>[
122
122
  leaf({
123
- name: 'heading-1',
124
- title: 'Heading 1',
125
- commandName: 'heading1'
126
- }),
123
+ name: 'code',
124
+ title: 'Code'
125
+ })
126
+ ]
127
+ },
128
+ leaf({
129
+ name: 'paragraph',
130
+ title: 'Paragraph'
131
+ })
132
+ ];
133
+ const request = resolver.resolve({
134
+ rootCommands,
135
+ filter: 'code',
136
+ path: [],
137
+ editor
138
+ });
139
+ const result = await request.promise;
140
+ expect(result.commands).toHaveLength(0);
141
+ });
142
+ it('searches only current nested level', async ()=>{
143
+ const resolver = new CommandsResolver();
144
+ const rootCommands = [
145
+ {
146
+ name: 'insert',
147
+ title: 'Insert',
148
+ commandName: 'insert',
149
+ icon: null,
150
+ getCommands: ()=>[
127
151
  leaf({
128
152
  name: 'code',
129
- title: 'Code',
130
- commandName: 'code'
153
+ title: 'Code'
131
154
  })
132
155
  ]
133
156
  }
@@ -135,13 +158,18 @@ describe('CommandsResolver', ()=>{
135
158
  const request = resolver.resolve({
136
159
  rootCommands,
137
160
  filter: 'code',
138
- path: [],
161
+ path: [
162
+ {
163
+ name: 'insert',
164
+ title: 'Insert',
165
+ commandName: 'insert'
166
+ }
167
+ ],
139
168
  editor
140
169
  });
141
170
  const result = await request.promise;
142
171
  expect(result.commands).toHaveLength(1);
143
172
  expect(result.commands[0]?.command.name).toBe('code');
144
- expect(result.commands[0]?.breadcrumb).toBe('Insert');
145
173
  });
146
174
  it('returns matching submenu commands in query mode', async ()=>{
147
175
  const resolver = new CommandsResolver();
@@ -189,13 +217,25 @@ describe('CommandsResolver', ()=>{
189
217
  const firstRequest = resolver.resolve({
190
218
  rootCommands,
191
219
  filter: 'a',
192
- path: [],
220
+ path: [
221
+ {
222
+ name: 'remote',
223
+ title: 'Remote',
224
+ commandName: 'remote'
225
+ }
226
+ ],
193
227
  editor
194
228
  });
195
229
  const secondRequest = resolver.resolve({
196
230
  rootCommands,
197
231
  filter: 'b',
198
- path: [],
232
+ path: [
233
+ {
234
+ name: 'remote',
235
+ title: 'Remote',
236
+ commandName: 'remote'
237
+ }
238
+ ],
199
239
  editor
200
240
  });
201
241
  searchB.resolve([
@@ -257,7 +297,13 @@ describe('CommandsResolver', ()=>{
257
297
  const loadingRequest = resolver.resolve({
258
298
  rootCommands,
259
299
  filter: 'code',
260
- path: [],
300
+ path: [
301
+ {
302
+ name: 'remote',
303
+ title: 'Remote',
304
+ commandName: 'remote'
305
+ }
306
+ ],
261
307
  editor
262
308
  });
263
309
  expect(loadingRequest.state.isLoading).toBe(true);
@@ -5,9 +5,7 @@ const styles_module = {
5
5
  active: "active-Is5D6b",
6
6
  icon: "icon-Xca6dM",
7
7
  content: "content-VZW7lK",
8
- breadcrumb: "breadcrumb-Jr0wXh",
9
8
  submenu: "submenu-zNsqOg",
10
- path: "path-fYY_14",
11
9
  systemRow: "systemRow-ln5twO",
12
10
  backdrop: "backdrop-lw7AjW"
13
11
  };
@@ -8,7 +8,7 @@
8
8
  will-change: transform, opacity;
9
9
  contain: layout paint style;
10
10
  backface-visibility: hidden;
11
- border-radius: 4px;
11
+ border-radius: 8px;
12
12
  flex-direction: column;
13
13
  max-height: 200px;
14
14
  margin-top: -6px;
@@ -70,32 +70,16 @@
70
70
  }
71
71
 
72
72
  .content-VZW7lK {
73
- flex-direction: column;
73
+ flex-direction: row;
74
74
  flex: 1;
75
- row-gap: 2px;
76
75
  min-width: 0;
77
76
  display: flex;
78
77
  }
79
78
 
80
- .breadcrumb-Jr0wXh {
81
- color: var(--kona-editor-secondary-text-color, #777);
82
- white-space: nowrap;
83
- text-overflow: ellipsis;
84
- font-size: 11px;
85
- overflow: hidden;
86
- }
87
-
88
79
  .submenu-zNsqOg {
89
80
  color: var(--kona-editor-secondary-text-color, #777);
90
81
  }
91
82
 
92
- .path-fYY_14 {
93
- color: var(--kona-editor-secondary-text-color, #777);
94
- border-bottom: 1px solid var(--kona-editor-border-color, #ddd);
95
- padding: 6px 8px;
96
- font-size: 11px;
97
- }
98
-
99
83
  .systemRow-ln5twO {
100
84
  min-height: 32px;
101
85
  color: var(--kona-editor-secondary-text-color, #777);
@@ -10,14 +10,35 @@ const useResolvedCommands = (params)=>{
10
10
  const { rootCommands, filter, path, editor, isOpen } = params;
11
11
  const resolverRef = useRef(new CommandsResolver());
12
12
  const [state, setState] = useState(EMPTY_STATE);
13
+ const prevIsOpenRef = useRef(false);
14
+ const prevPathKeyRef = useRef('');
15
+ const prevQueryRef = useRef('');
13
16
  const query = 'string' == typeof filter ? filter : '';
14
17
  useEffect(()=>{
15
- if (!isOpen || false === filter) return void setState(EMPTY_STATE);
16
- setState({
18
+ if (!isOpen || false === filter) {
19
+ setState(EMPTY_STATE);
20
+ prevIsOpenRef.current = false;
21
+ prevPathKeyRef.current = '';
22
+ prevQueryRef.current = '';
23
+ return;
24
+ }
25
+ const pathKey = path.map((item)=>item.name).join('/');
26
+ const isNewSession = !prevIsOpenRef.current;
27
+ const isPathChanged = !isNewSession && prevPathKeyRef.current !== pathKey;
28
+ const isQueryChanged = !isNewSession && prevQueryRef.current !== query;
29
+ if (isNewSession || isPathChanged) setState({
17
30
  commands: [],
18
31
  isLoading: true,
19
32
  isError: false
20
33
  });
34
+ else if (isQueryChanged) setState((state)=>({
35
+ ...state,
36
+ isLoading: true,
37
+ isError: false
38
+ }));
39
+ prevIsOpenRef.current = true;
40
+ prevPathKeyRef.current = pathKey;
41
+ prevQueryRef.current = query;
21
42
  const timeout = window.setTimeout(()=>{
22
43
  const request = resolverRef.current.resolve({
23
44
  rootCommands,
@@ -25,7 +46,6 @@ const useResolvedCommands = (params)=>{
25
46
  path,
26
47
  editor
27
48
  });
28
- setState(request.state);
29
49
  request.promise.then((resolved)=>{
30
50
  setState(resolved);
31
51
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@use-kona/editor",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
@@ -44,7 +44,6 @@ export const Menu = (props: Props) => {
44
44
  });
45
45
 
46
46
  const isBrowseMode = typeof store.filter === 'string' && store.filter === '';
47
- const isSearchMode = typeof store.filter === 'string' && store.filter !== '';
48
47
 
49
48
  const { commands, isLoading, isError } = useResolvedCommands({
50
49
  rootCommands,
@@ -87,10 +86,13 @@ export const Menu = (props: Props) => {
87
86
  }, [store.isOpen, store.openId]);
88
87
 
89
88
  useEffect(() => {
90
- if (store.filter === false || isSearchMode) {
89
+ if (
90
+ store.filter === false ||
91
+ (typeof store.filter === 'string' && store.filter !== '')
92
+ ) {
91
93
  setActive(0);
92
94
  }
93
- }, [isSearchMode, store.filter]);
95
+ }, [store.filter]);
94
96
 
95
97
  useEffect(() => {
96
98
  if (!entries.length) {
@@ -268,8 +270,6 @@ export const Menu = (props: Props) => {
268
270
  return null;
269
271
  }
270
272
 
271
- const pathLabel = path.map((item) => item.title).join(' / ');
272
-
273
273
  return createPortal(
274
274
  renderMenu(
275
275
  <>
@@ -289,9 +289,6 @@ export const Menu = (props: Props) => {
289
289
  event.preventDefault();
290
290
  }}
291
291
  >
292
- {isBrowseMode && pathLabel && (
293
- <div className={styles.path}>{pathLabel}</div>
294
- )}
295
292
  {entries.map((entry, index) => {
296
293
  if (entry.type === 'back') {
297
294
  return (
@@ -348,11 +345,6 @@ export const Menu = (props: Props) => {
348
345
  </span>
349
346
  <span className={styles.content}>
350
347
  <span>{entry.command.command.title}</span>
351
- {isSearchMode && entry.command.breadcrumb && (
352
- <span className={styles.breadcrumb}>
353
- {entry.command.breadcrumb}
354
- </span>
355
- )}
356
348
  </span>
357
349
  {entry.command.isSubmenu && isBrowseMode && (
358
350
  <span className={styles.submenu} aria-hidden="true">
@@ -102,7 +102,7 @@ describe('CommandsResolver', () => {
102
102
  expect(result.commands[0]?.command.name).toBe('code');
103
103
  });
104
104
 
105
- it('returns global leaf query matches with breadcrumbs', async () => {
105
+ it('searches only root level when path is empty', async () => {
106
106
  const resolver = new CommandsResolver();
107
107
  const rootCommands: Command[] = [
108
108
  {
@@ -110,15 +110,9 @@ describe('CommandsResolver', () => {
110
110
  title: 'Insert',
111
111
  commandName: 'insert',
112
112
  icon: null,
113
- getCommands: () => [
114
- leaf({
115
- name: 'heading-1',
116
- title: 'Heading 1',
117
- commandName: 'heading1',
118
- }),
119
- leaf({ name: 'code', title: 'Code', commandName: 'code' }),
120
- ],
113
+ getCommands: () => [leaf({ name: 'code', title: 'Code' })],
121
114
  },
115
+ leaf({ name: 'paragraph', title: 'Paragraph' }),
122
116
  ];
123
117
 
124
118
  const request = resolver.resolve({
@@ -130,9 +124,32 @@ describe('CommandsResolver', () => {
130
124
 
131
125
  const result = await request.promise;
132
126
 
127
+ expect(result.commands).toHaveLength(0);
128
+ });
129
+
130
+ it('searches only current nested level', async () => {
131
+ const resolver = new CommandsResolver();
132
+ const rootCommands: Command[] = [
133
+ {
134
+ name: 'insert',
135
+ title: 'Insert',
136
+ commandName: 'insert',
137
+ icon: null,
138
+ getCommands: () => [leaf({ name: 'code', title: 'Code' })],
139
+ },
140
+ ];
141
+
142
+ const request = resolver.resolve({
143
+ rootCommands,
144
+ filter: 'code',
145
+ path: [{ name: 'insert', title: 'Insert', commandName: 'insert' }],
146
+ editor,
147
+ });
148
+
149
+ const result = await request.promise;
150
+
133
151
  expect(result.commands).toHaveLength(1);
134
152
  expect(result.commands[0]?.command.name).toBe('code');
135
- expect(result.commands[0]?.breadcrumb).toBe('Insert');
136
153
  });
137
154
 
138
155
  it('returns matching submenu commands in query mode', async () => {
@@ -185,13 +202,13 @@ describe('CommandsResolver', () => {
185
202
  const firstRequest = resolver.resolve({
186
203
  rootCommands,
187
204
  filter: 'a',
188
- path: [],
205
+ path: [{ name: 'remote', title: 'Remote', commandName: 'remote' }],
189
206
  editor,
190
207
  });
191
208
  const secondRequest = resolver.resolve({
192
209
  rootCommands,
193
210
  filter: 'b',
194
- path: [],
211
+ path: [{ name: 'remote', title: 'Remote', commandName: 'remote' }],
195
212
  editor,
196
213
  });
197
214
 
@@ -243,7 +260,7 @@ describe('CommandsResolver', () => {
243
260
  const loadingRequest = resolver.resolve({
244
261
  rootCommands,
245
262
  filter: 'code',
246
- path: [],
263
+ path: [{ name: 'remote', title: 'Remote', commandName: 'remote' }],
247
264
  editor,
248
265
  });
249
266
 
@@ -16,7 +16,6 @@ export type ResolvedCommand = {
16
16
  command: Command;
17
17
  key: string;
18
18
  path: CommandPathEntry[];
19
- breadcrumb: string;
20
19
  isSubmenu: boolean;
21
20
  };
22
21
 
@@ -84,36 +83,57 @@ const toResolvedCommand = (
84
83
  command,
85
84
  path,
86
85
  key: pathToKey(path),
87
- breadcrumb: parentPath.map((item) => item.title).join(' / '),
88
86
  isSubmenu: Boolean(command.getCommands),
89
87
  };
90
88
  };
91
89
 
92
- const resolveBrowseCommands = async (
90
+ const resolveCurrentLevelCommands = async (
93
91
  params: ResolveCommandsParams,
94
92
  resolveChildCommands: ResolveChildCommands,
93
+ queryForCurrentLevel: string,
95
94
  ) => {
96
95
  const { rootCommands, path, editor } = params;
97
96
  let currentCommands = rootCommands;
98
97
  let currentPath: CommandPathEntry[] = [];
99
98
 
100
- for (const item of path) {
99
+ for (let index = 0; index < path.length; index++) {
100
+ const item = path[index];
101
+ const isLastPathItem = index === path.length - 1;
101
102
  const command = currentCommands.find((entry) => entry.name === item.name);
102
103
  if (!command?.getCommands) {
103
- return [];
104
+ return {
105
+ commands: [],
106
+ path: currentPath,
107
+ };
104
108
  }
105
109
 
106
110
  currentPath = [...currentPath, toPathEntry(command)];
107
111
  currentCommands = await resolveChildCommands({
108
112
  command,
109
113
  path: currentPath,
110
- query: '',
114
+ query: isLastPathItem ? queryForCurrentLevel : '',
111
115
  editor,
112
116
  });
113
117
  }
114
118
 
115
- return currentCommands.map((command) =>
116
- toResolvedCommand(command, currentPath),
119
+ return {
120
+ commands: currentCommands,
121
+ path: currentPath,
122
+ };
123
+ };
124
+
125
+ const resolveBrowseCommands = async (
126
+ params: ResolveCommandsParams,
127
+ resolveChildCommands: ResolveChildCommands,
128
+ ) => {
129
+ const currentLevel = await resolveCurrentLevelCommands(
130
+ params,
131
+ resolveChildCommands,
132
+ '',
133
+ );
134
+
135
+ return currentLevel.commands.map((command) =>
136
+ toResolvedCommand(command, currentLevel.path),
117
137
  );
118
138
  };
119
139
 
@@ -121,38 +141,20 @@ const resolveSearchCommands = async (
121
141
  params: ResolveCommandsParams,
122
142
  resolveChildCommands: ResolveChildCommands,
123
143
  ) => {
124
- const { rootCommands, filter, editor } = params;
125
- const commands: ResolvedCommand[] = [];
126
-
127
- const walk = async (
128
- levelCommands: Command[],
129
- parentPath: CommandPathEntry[],
130
- ): Promise<void> => {
131
- for (const command of levelCommands) {
132
- if (command.getCommands) {
133
- if (isCommandMatchesQuery(command, filter)) {
134
- commands.push(toResolvedCommand(command, parentPath));
135
- }
144
+ const { filter } = params;
145
+ const currentLevel = await resolveCurrentLevelCommands(
146
+ params,
147
+ resolveChildCommands,
148
+ filter,
149
+ );
136
150
 
137
- const currentPath = [...parentPath, toPathEntry(command)];
138
- const children = await resolveChildCommands({
139
- command,
140
- path: currentPath,
141
- query: filter,
142
- editor,
143
- });
144
- await walk(children, currentPath);
145
- continue;
146
- }
147
-
148
- if (command.action && isCommandMatchesQuery(command, filter)) {
149
- commands.push(toResolvedCommand(command, parentPath));
150
- }
151
- }
152
- };
151
+ const matchedCommands = currentLevel.commands.filter((command) =>
152
+ isCommandMatchesQuery(command, filter),
153
+ );
153
154
 
154
- await walk(rootCommands, []);
155
- return commands;
155
+ return matchedCommands.map((command) =>
156
+ toResolvedCommand(command, currentLevel.path),
157
+ );
156
158
  };
157
159
 
158
160
  export class CommandsResolver {
@@ -11,7 +11,7 @@
11
11
  background-color: var(--kona-editor-background-color, #fff);
12
12
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.025);
13
13
  border: 1px solid var(--kona-editor-border-color, #ddd);
14
- border-radius: 4px;
14
+ border-radius: 8px;
15
15
  transition:
16
16
  transform 0.12s ease,
17
17
  opacity 0.12s ease;
@@ -79,29 +79,13 @@
79
79
  display: flex;
80
80
  flex: 1;
81
81
  min-width: 0;
82
- flex-direction: column;
83
- row-gap: 2px;
84
- }
85
-
86
- .breadcrumb {
87
- font-size: 11px;
88
- color: var(--kona-editor-secondary-text-color, #777);
89
- white-space: nowrap;
90
- overflow: hidden;
91
- text-overflow: ellipsis;
82
+ flex-direction: row;
92
83
  }
93
84
 
94
85
  .submenu {
95
86
  color: var(--kona-editor-secondary-text-color, #777);
96
87
  }
97
88
 
98
- .path {
99
- padding: 6px 8px;
100
- font-size: 11px;
101
- color: var(--kona-editor-secondary-text-color, #777);
102
- border-bottom: 1px solid var(--kona-editor-border-color, #ddd);
103
- }
104
-
105
89
  .systemRow {
106
90
  min-height: 32px;
107
91
  padding: 8px;
@@ -26,19 +26,42 @@ export const useResolvedCommands = (params: Params) => {
26
26
  const { rootCommands, filter, path, editor, isOpen } = params;
27
27
  const resolverRef = useRef(new CommandsResolver());
28
28
  const [state, setState] = useState<ResolvedCommandsState>(EMPTY_STATE);
29
+ const prevIsOpenRef = useRef(false);
30
+ const prevPathKeyRef = useRef('');
31
+ const prevQueryRef = useRef('');
29
32
  const query = typeof filter === 'string' ? filter : '';
30
33
 
31
34
  useEffect(() => {
32
35
  if (!isOpen || filter === false) {
33
36
  setState(EMPTY_STATE);
37
+ prevIsOpenRef.current = false;
38
+ prevPathKeyRef.current = '';
39
+ prevQueryRef.current = '';
34
40
  return;
35
41
  }
36
42
 
37
- setState({
38
- commands: [],
39
- isLoading: true,
40
- isError: false,
41
- });
43
+ const pathKey = path.map((item) => item.name).join('/');
44
+ const isNewSession = !prevIsOpenRef.current;
45
+ const isPathChanged = !isNewSession && prevPathKeyRef.current !== pathKey;
46
+ const isQueryChanged = !isNewSession && prevQueryRef.current !== query;
47
+
48
+ if (isNewSession || isPathChanged) {
49
+ setState({
50
+ commands: [],
51
+ isLoading: true,
52
+ isError: false,
53
+ });
54
+ } else if (isQueryChanged) {
55
+ setState((state) => ({
56
+ ...state,
57
+ isLoading: true,
58
+ isError: false,
59
+ }));
60
+ }
61
+
62
+ prevIsOpenRef.current = true;
63
+ prevPathKeyRef.current = pathKey;
64
+ prevQueryRef.current = query;
42
65
 
43
66
  const timeout = window.setTimeout(
44
67
  () => {
@@ -49,8 +72,6 @@ export const useResolvedCommands = (params: Params) => {
49
72
  editor,
50
73
  });
51
74
 
52
- setState(request.state);
53
-
54
75
  request.promise.then((resolved) => {
55
76
  setState(resolved);
56
77
  });