Skip to content

Commit 342e9c6

Browse files
committed
list like input field improvements
1 parent 1b4eb72 commit 342e9c6

File tree

14 files changed

+342
-12
lines changed

14 files changed

+342
-12
lines changed

packages/core/src/api/InternalAPI.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import ErrorCollectionComponent from 'packages/core/src/utils/errors/ErrorCollec
2626
import ErrorIndicatorComponent from 'packages/core/src/utils/errors/ErrorIndicatorComponent.svelte';
2727
import { SuggesterSelectModal } from 'packages/core/src/modals/selectModalContents/SuggesterSelectModal';
2828
import { type IFuzzySearch } from 'packages/core/src/utils/IFuzzySearch';
29+
import { type ContextMenuItemDefinition, type IContextMenu } from 'packages/core/src/utils/IContextMenu';
2930

3031
export interface ErrorIndicatorProps {
3132
errorCollection: ErrorCollection;
@@ -205,6 +206,8 @@ export abstract class InternalAPI<Plugin extends IPlugin> {
205206
*/
206207
abstract readFilePath(filePath: string): Promise<string>;
207208

209+
abstract createContextMenu(items: ContextMenuItemDefinition[]): IContextMenu;
210+
208211
openCommandSelectModal(selectCallback: (selected: Command) => void): void {
209212
this.createSearchModal(new CommandSelectModal(this.plugin, selectCallback)).open();
210213
}

packages/core/src/config/FieldConfigs.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export enum InputFieldArgumentType {
5454
PLACEHOLDER = 'placeholder',
5555
USE_LINKS = 'useLinks',
5656
LIMIT = 'limit',
57+
MULTI_LINE = 'multiLine',
58+
ALLOW_OTHER = 'allowOther',
5759

5860
INVALID = 'invalid',
5961
}
@@ -434,6 +436,38 @@ export const InputFieldArgumentConfigs: Record<InputFieldArgumentType, InputFiel
434436
],
435437
allowMultiple: false,
436438
},
439+
[InputFieldArgumentType.MULTI_LINE]: {
440+
type: InputFieldArgumentType.MULTI_LINE,
441+
allowedFieldTypes: [InputFieldType.LIST, InputFieldType.INLINE_LIST],
442+
values: [
443+
[
444+
{
445+
name: 'value',
446+
allowed: ['true', 'false'],
447+
description: '',
448+
},
449+
],
450+
],
451+
allowMultiple: false,
452+
},
453+
[InputFieldArgumentType.ALLOW_OTHER]: {
454+
type: InputFieldArgumentType.ALLOW_OTHER,
455+
allowedFieldTypes: [
456+
InputFieldType.SUGGESTER,
457+
InputFieldType.LIST_SUGGESTER,
458+
InputFieldType.INLINE_LIST_SUGGESTER,
459+
],
460+
values: [
461+
[
462+
{
463+
name: 'value',
464+
allowed: ['true', 'false'],
465+
description: '',
466+
},
467+
],
468+
],
469+
allowMultiple: false,
470+
},
437471
[InputFieldArgumentType.INVALID]: {
438472
type: InputFieldArgumentType.INVALID,
439473
allowedFieldTypes: [],
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { AbstractInputFieldArgument } from 'packages/core/src/fields/fieldArguments/inputFieldArguments/AbstractInputFieldArgument';
2+
import type { ParsingResultNode } from 'packages/core/src/parsers/nomParsers/GeneralNomParsers';
3+
import { type InputFieldArgumentConfig, InputFieldArgumentConfigs } from 'packages/core/src/config/FieldConfigs';
4+
5+
export class AllowOtherInputFieldArgument extends AbstractInputFieldArgument {
6+
value: boolean = true;
7+
8+
override _parseValue(value: ParsingResultNode[]): void {
9+
this.value = value[0] === undefined || value[0]?.value.toLowerCase() === 'true';
10+
}
11+
12+
public getConfig(): InputFieldArgumentConfig {
13+
return InputFieldArgumentConfigs.multiLine;
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { type InputFieldArgumentConfig, InputFieldArgumentConfigs } from 'packages/core/src/config/FieldConfigs';
2+
import { AbstractInputFieldArgument } from 'packages/core/src/fields/fieldArguments/inputFieldArguments/AbstractInputFieldArgument';
3+
import { type ParsingResultNode } from 'packages/core/src/parsers/nomParsers/GeneralNomParsers';
4+
5+
export class MultiLineInputFieldArgument extends AbstractInputFieldArgument {
6+
value: boolean = true;
7+
8+
override _parseValue(value: ParsingResultNode[]): void {
9+
this.value = value[0] === undefined || value[0]?.value.toLowerCase() === 'true';
10+
}
11+
12+
public getConfig(): InputFieldArgumentConfig {
13+
return InputFieldArgumentConfigs.multiLine;
14+
}
15+
}

packages/core/src/fields/inputFields/fields/InlineList/InlineListComponent.svelte

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script lang="ts">
22
import Icon from '../../../../utils/components/Icon.svelte';
3-
import { MBLiteral } from '../../../../utils/Literal';
3+
import { MBLiteral, stringifyLiteral } from '../../../../utils/Literal';
44
import LiteralRenderComponent from '../../../../utils/components/LiteralRenderComponent.svelte';
55
import { IPlugin } from '../../../../IPlugin';
6+
import { ContextMenuItemDefinition } from 'packages/core/src/utils/IContextMenu';
67
78
export let plugin: IPlugin;
89
export let value: MBLiteral[];
@@ -39,14 +40,72 @@
3940
showInput();
4041
}
4142
}
43+
44+
function openContextMenuForElement(e: MouseEvent, index: number) {
45+
const menuActions: ContextMenuItemDefinition[] = [];
46+
47+
if (index > 0) {
48+
menuActions.push({
49+
name: 'Move left',
50+
icon: 'arrow-left',
51+
onclick: () => {
52+
const temp = value[index - 1];
53+
value[index - 1] = value[index];
54+
value[index] = temp;
55+
onValueChange(value);
56+
},
57+
});
58+
}
59+
60+
if (index < value.length - 1) {
61+
menuActions.push({
62+
name: 'Move right',
63+
icon: 'arrow-right',
64+
onclick: () => {
65+
const temp = value[index + 1];
66+
value[index + 1] = value[index];
67+
value[index] = temp;
68+
onValueChange(value);
69+
},
70+
});
71+
}
72+
73+
menuActions.push({
74+
name: 'Edit',
75+
icon: 'pencil',
76+
onclick: () => {
77+
// TODO: this needs the text prompt modal
78+
plugin.internal.openTextPromptModal(
79+
stringifyLiteral(value[index]),
80+
'Edit List Item',
81+
'Edit the value of this list item.',
82+
'',
83+
v => {
84+
value[index] = v;
85+
onValueChange(value);
86+
},
87+
() => {},
88+
);
89+
},
90+
});
91+
92+
menuActions.push({
93+
name: 'Remove',
94+
icon: 'x',
95+
warning: true,
96+
onclick: () => remove(index),
97+
});
98+
99+
plugin.internal.createContextMenu(menuActions).showWithEvent(e);
100+
}
42101
</script>
43102

44103
<div class="mb-inline-list">
45104
{#each value as entry, i}
46105
<div class="mb-inline-list-item">
47106
<LiteralRenderComponent value={entry}></LiteralRenderComponent>
48-
<button class="mb-inline-list-item-button" on:click={() => remove(i)}>
49-
<Icon plugin={plugin} iconName="x" />
107+
<button class="mb-inline-list-item-button" on:click={e => openContextMenuForElement(e, i)}>
108+
<Icon plugin={plugin} iconName="more-vertical" />
50109
</button>
51110
</div>
52111
{/each}

packages/core/src/fields/inputFields/fields/InlineListSuggester/InlineListSuggesterComponent.svelte

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script lang="ts">
22
import Icon from '../../../../utils/components/Icon.svelte';
3-
import { MBLiteral } from '../../../../utils/Literal';
3+
import { MBLiteral, stringifyLiteral } from '../../../../utils/Literal';
44
import LiteralRenderComponent from '../../../../utils/components/LiteralRenderComponent.svelte';
55
import { IPlugin } from '../../../../IPlugin';
6+
import { ContextMenuItemDefinition } from 'packages/core/src/utils/IContextMenu';
67
78
export let plugin: IPlugin;
89
export let value: MBLiteral[];
@@ -39,14 +40,53 @@
3940
showSuggester();
4041
}
4142
}
43+
44+
function openContextMenuForElement(e: MouseEvent, index: number) {
45+
const menuActions: ContextMenuItemDefinition[] = [];
46+
47+
if (index > 0) {
48+
menuActions.push({
49+
name: 'Move left',
50+
icon: 'arrow-left',
51+
onclick: () => {
52+
const temp = value[index - 1];
53+
value[index - 1] = value[index];
54+
value[index] = temp;
55+
onValueChange(value);
56+
},
57+
});
58+
}
59+
60+
if (index < value.length - 1) {
61+
menuActions.push({
62+
name: 'Move right',
63+
icon: 'arrow-right',
64+
onclick: () => {
65+
const temp = value[index + 1];
66+
value[index + 1] = value[index];
67+
value[index] = temp;
68+
onValueChange(value);
69+
},
70+
});
71+
}
72+
73+
menuActions.push({
74+
name: 'Remove',
75+
icon: 'x',
76+
warning: true,
77+
onclick: () => remove(index),
78+
});
79+
80+
plugin.internal.createContextMenu(menuActions).showWithEvent(e);
81+
}
4282
</script>
4383

4484
<div class="mb-inline-list">
4585
{#each value as entry, i}
4686
<div class="mb-inline-list-item">
4787
<LiteralRenderComponent value={entry}></LiteralRenderComponent>
48-
<button class="mb-inline-list-item-button" on:click={() => remove(i)}>
49-
<Icon plugin={plugin} iconName="x" />
88+
<button class="mb-inline-list-item-button" on:click={e => openContextMenuForElement(e, i)}>
89+
<Icon plugin={plugin} iconName="more-vertical" />
5090
</button>
5191
</div>
5292
{/each}

packages/core/src/fields/inputFields/fields/List/ListComponent.svelte

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<script lang="ts">
22
import Icon from '../../../../utils/components/Icon.svelte';
3-
import { MBLiteral } from '../../../../utils/Literal';
3+
import { MBLiteral, stringifyLiteral } from '../../../../utils/Literal';
44
import LiteralRenderComponent from '../../../../utils/components/LiteralRenderComponent.svelte';
55
import Button from '../../../../utils/components/Button.svelte';
66
import { IPlugin } from '../../../../IPlugin';
7+
import { ContextMenuItemDefinition } from 'packages/core/src/utils/IContextMenu';
78
89
export let plugin: IPlugin;
910
export let value: MBLiteral[];
@@ -39,14 +40,72 @@
3940
const lengthStr = length.toString().padStart(limitStr.length, '0');
4041
return `${lengthStr}/${limitStr}`;
4142
}
43+
44+
function openContextMenuForElement(e: MouseEvent, index: number) {
45+
const menuActions: ContextMenuItemDefinition[] = [];
46+
47+
if (index > 0) {
48+
menuActions.push({
49+
name: 'Move up',
50+
icon: 'arrow-up',
51+
onclick: () => {
52+
const temp = value[index - 1];
53+
value[index - 1] = value[index];
54+
value[index] = temp;
55+
onValueChange(value);
56+
},
57+
});
58+
}
59+
60+
if (index < value.length - 1) {
61+
menuActions.push({
62+
name: 'Move down',
63+
icon: 'arrow-down',
64+
onclick: () => {
65+
const temp = value[index + 1];
66+
value[index + 1] = value[index];
67+
value[index] = temp;
68+
onValueChange(value);
69+
},
70+
});
71+
}
72+
73+
menuActions.push({
74+
name: 'Edit',
75+
icon: 'pencil',
76+
onclick: () => {
77+
// TODO: this needs the text prompt modal
78+
plugin.internal.openTextPromptModal(
79+
stringifyLiteral(value[index]),
80+
'Edit List Item',
81+
'Edit the value of this list item.',
82+
'',
83+
v => {
84+
value[index] = v;
85+
onValueChange(value);
86+
},
87+
() => {},
88+
);
89+
},
90+
});
91+
92+
menuActions.push({
93+
name: 'Remove',
94+
icon: 'x',
95+
warning: true,
96+
onclick: () => remove(index),
97+
});
98+
99+
plugin.internal.createContextMenu(menuActions).showWithEvent(e);
100+
}
42101
</script>
43102

44103
<div class="mb-list-items">
45104
{#each value as entry, i}
46105
<div class="mb-list-item">
47106
<LiteralRenderComponent value={entry}></LiteralRenderComponent>
48-
<Button on:click={() => remove(i)}>
49-
<Icon plugin={plugin} iconName="x" />
107+
<Button on:click={e => openContextMenuForElement(e, i)}>
108+
<Icon plugin={plugin} iconName="more-vertical" />
50109
</Button>
51110
</div>
52111
{:else}

0 commit comments

Comments
 (0)