@real1ty-obsidian-plugins/utils 2.0.1 → 2.1.0
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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/settings-ui-builder.d.ts +58 -0
- package/dist/settings-ui-builder.d.ts.map +1 -0
- package/dist/settings-ui-builder.js +218 -0
- package/dist/settings-ui-builder.js.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./frontmatter-utils";
|
|
|
10
10
|
export * from "./generate";
|
|
11
11
|
export * from "./link-parser";
|
|
12
12
|
export * from "./settings-store";
|
|
13
|
+
export * from "./settings-ui-builder";
|
|
13
14
|
export * from "./string-utils";
|
|
14
15
|
export * from "./templater-utils";
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./frontmatter-utils";
|
|
|
10
10
|
export * from "./generate";
|
|
11
11
|
export * from "./link-parser";
|
|
12
12
|
export * from "./settings-store";
|
|
13
|
+
export * from "./settings-ui-builder";
|
|
13
14
|
export * from "./string-utils";
|
|
14
15
|
export * from "./templater-utils";
|
|
15
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC","sourcesContent":["export * from \"./async-utils\";\nexport * from \"./batch-operations\";\nexport * from \"./child-reference-utils\";\nexport * from \"./date-recurrence-utils\";\nexport * from \"./date-utils\";\nexport * from \"./evaluator-base\";\nexport * from \"./file-operations\";\nexport * from \"./file-utils\";\nexport * from \"./frontmatter-utils\";\nexport * from \"./generate\";\nexport * from \"./link-parser\";\nexport * from \"./settings-store\";\nexport * from \"./string-utils\";\nexport * from \"./templater-utils\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC","sourcesContent":["export * from \"./async-utils\";\nexport * from \"./batch-operations\";\nexport * from \"./child-reference-utils\";\nexport * from \"./date-recurrence-utils\";\nexport * from \"./date-utils\";\nexport * from \"./evaluator-base\";\nexport * from \"./file-operations\";\nexport * from \"./file-utils\";\nexport * from \"./frontmatter-utils\";\nexport * from \"./generate\";\nexport * from \"./link-parser\";\nexport * from \"./settings-store\";\nexport * from \"./settings-ui-builder\";\nexport * from \"./string-utils\";\nexport * from \"./templater-utils\";\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ZodObject, ZodRawShape } from "zod";
|
|
2
|
+
import type { SettingsStore } from "./settings-store";
|
|
3
|
+
interface BaseSettingConfig {
|
|
4
|
+
key: string;
|
|
5
|
+
name: string;
|
|
6
|
+
desc: string;
|
|
7
|
+
}
|
|
8
|
+
interface TextSettingConfig extends BaseSettingConfig {
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
}
|
|
11
|
+
interface SliderSettingConfig extends BaseSettingConfig {
|
|
12
|
+
min?: number;
|
|
13
|
+
max?: number;
|
|
14
|
+
step?: number;
|
|
15
|
+
}
|
|
16
|
+
interface ArraySettingConfig extends BaseSettingConfig {
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
arrayDelimiter?: string;
|
|
19
|
+
multiline?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface ArrayManagerConfig extends BaseSettingConfig {
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
addButtonText?: string;
|
|
24
|
+
removeButtonText?: string;
|
|
25
|
+
emptyArrayFallback?: unknown;
|
|
26
|
+
preventEmpty?: boolean;
|
|
27
|
+
itemDescriptionFn?: (item: unknown) => string;
|
|
28
|
+
onBeforeAdd?: (newItem: unknown, currentItems: unknown[]) => unknown[] | Promise<unknown[]>;
|
|
29
|
+
onBeforeRemove?: (itemToRemove: unknown, currentItems: unknown[]) => unknown[] | Promise<unknown[]>;
|
|
30
|
+
quickActions?: Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
desc: string;
|
|
33
|
+
buttonText: string;
|
|
34
|
+
condition?: (currentItems: unknown[]) => boolean;
|
|
35
|
+
action: (currentItems: unknown[]) => unknown[] | Promise<unknown[]>;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
export declare class SettingsUIBuilder<TSchema extends ZodObject<ZodRawShape>> {
|
|
39
|
+
private settingsStore;
|
|
40
|
+
constructor(settingsStore: SettingsStore<TSchema>);
|
|
41
|
+
private get settings();
|
|
42
|
+
private updateSetting;
|
|
43
|
+
addToggle(containerEl: HTMLElement, config: BaseSettingConfig): void;
|
|
44
|
+
addSlider(containerEl: HTMLElement, config: SliderSettingConfig): void;
|
|
45
|
+
addText(containerEl: HTMLElement, config: TextSettingConfig): void;
|
|
46
|
+
addTextArray(containerEl: HTMLElement, config: ArraySettingConfig): void;
|
|
47
|
+
/**
|
|
48
|
+
* Advanced array manager with add/remove buttons for each item
|
|
49
|
+
* Similar to the directory settings pattern
|
|
50
|
+
*/
|
|
51
|
+
addArrayManager(containerEl: HTMLElement, config: ArrayManagerConfig): void;
|
|
52
|
+
/**
|
|
53
|
+
* Automatically detect the type from current value and create appropriate control
|
|
54
|
+
*/
|
|
55
|
+
auto(containerEl: HTMLElement, config: TextSettingConfig & SliderSettingConfig & ArraySettingConfig): void;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=settings-ui-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-ui-builder.d.ts","sourceRoot":"","sources":["../src/settings-ui-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAK,MAAM,KAAK,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,UAAU,iBAAiB;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,UAAU,iBAAkB,SAAQ,iBAAiB;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,mBAAoB,SAAQ,iBAAiB;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,kBAAmB,SAAQ,iBAAiB;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,kBAAmB,SAAQ,iBAAiB;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5F,cAAc,CAAC,EAAE,CAChB,YAAY,EAAE,OAAO,EACrB,YAAY,EAAE,OAAO,EAAE,KACnB,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACpC,YAAY,CAAC,EAAE,KAAK,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;QACjD,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;KACpE,CAAC,CAAC;CACH;AAED,qBAAa,iBAAiB,CAAC,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC;IACxD,OAAO,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC;IAEzD,OAAO,KAAK,QAAQ,GAEnB;YAEa,aAAa;IAU3B,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAcpE,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI;IAoBtE,OAAO,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAiBlE,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IA6CxE;;;OAGG;IACH,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAkI3E;;OAEG;IACH,IAAI,CACH,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,kBAAkB,GAClE,IAAI;CAgBP"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { Setting } from "obsidian";
|
|
3
|
+
export class SettingsUIBuilder {
|
|
4
|
+
constructor(settingsStore) {
|
|
5
|
+
this.settingsStore = settingsStore;
|
|
6
|
+
}
|
|
7
|
+
get settings() {
|
|
8
|
+
return this.settingsStore.currentSettings;
|
|
9
|
+
}
|
|
10
|
+
updateSetting(key, value) {
|
|
11
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12
|
+
yield this.settingsStore.updateSettings((s) => (Object.assign(Object.assign({}, s), { [key]: value })));
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
addToggle(containerEl, config) {
|
|
16
|
+
const { key, name, desc } = config;
|
|
17
|
+
const value = this.settings[key];
|
|
18
|
+
new Setting(containerEl)
|
|
19
|
+
.setName(name)
|
|
20
|
+
.setDesc(desc)
|
|
21
|
+
.addToggle((toggle) => toggle.setValue(Boolean(value)).onChange((newValue) => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
yield this.updateSetting(key, newValue);
|
|
23
|
+
})));
|
|
24
|
+
}
|
|
25
|
+
addSlider(containerEl, config) {
|
|
26
|
+
const { key, name, desc, min = 0, max = 100, step = 1 } = config;
|
|
27
|
+
const value = this.settings[key];
|
|
28
|
+
new Setting(containerEl)
|
|
29
|
+
.setName(name)
|
|
30
|
+
.setDesc(desc)
|
|
31
|
+
.addSlider((slider) => {
|
|
32
|
+
slider
|
|
33
|
+
.setLimits(min, max, step)
|
|
34
|
+
.setValue(Number(value))
|
|
35
|
+
.setDynamicTooltip()
|
|
36
|
+
.onChange((newValue) => __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
yield this.updateSetting(key, newValue);
|
|
38
|
+
}));
|
|
39
|
+
return slider;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
addText(containerEl, config) {
|
|
43
|
+
const { key, name, desc, placeholder = "" } = config;
|
|
44
|
+
const value = this.settings[key];
|
|
45
|
+
new Setting(containerEl)
|
|
46
|
+
.setName(name)
|
|
47
|
+
.setDesc(desc)
|
|
48
|
+
.addText((text) => text
|
|
49
|
+
.setPlaceholder(placeholder)
|
|
50
|
+
.setValue(String(value !== null && value !== void 0 ? value : ""))
|
|
51
|
+
.onChange((newValue) => __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
yield this.updateSetting(key, newValue);
|
|
53
|
+
})));
|
|
54
|
+
}
|
|
55
|
+
addTextArray(containerEl, config) {
|
|
56
|
+
const { key, name, desc, placeholder = "", arrayDelimiter = ", ", multiline = false } = config;
|
|
57
|
+
const value = this.settings[key];
|
|
58
|
+
const setting = new Setting(containerEl).setName(name).setDesc(desc);
|
|
59
|
+
if (multiline) {
|
|
60
|
+
setting.addTextArea((text) => {
|
|
61
|
+
text.setPlaceholder(placeholder);
|
|
62
|
+
text.setValue(Array.isArray(value) ? value.join("\n") : "");
|
|
63
|
+
const commit = (inputValue) => __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
const items = inputValue
|
|
65
|
+
.split("\n")
|
|
66
|
+
.map((s) => s.trim())
|
|
67
|
+
.filter((s) => s.length > 0);
|
|
68
|
+
yield this.updateSetting(key, items);
|
|
69
|
+
});
|
|
70
|
+
text.inputEl.addEventListener("blur", () => void commit(text.inputEl.value));
|
|
71
|
+
text.inputEl.addEventListener("keydown", (e) => {
|
|
72
|
+
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
void commit(text.inputEl.value);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
text.inputEl.rows = 5;
|
|
78
|
+
text.inputEl.classList.add("settings-ui-builder-textarea");
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
setting.addText((text) => {
|
|
83
|
+
text.setPlaceholder(placeholder);
|
|
84
|
+
text.setValue(Array.isArray(value) ? value.join(arrayDelimiter) : "");
|
|
85
|
+
text.onChange((inputValue) => __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
const items = inputValue
|
|
87
|
+
.split(",")
|
|
88
|
+
.map((s) => s.trim())
|
|
89
|
+
.filter((s) => s.length > 0);
|
|
90
|
+
yield this.updateSetting(key, items);
|
|
91
|
+
}));
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Advanced array manager with add/remove buttons for each item
|
|
97
|
+
* Similar to the directory settings pattern
|
|
98
|
+
*/
|
|
99
|
+
addArrayManager(containerEl, config) {
|
|
100
|
+
var _a;
|
|
101
|
+
const { key, name, desc, placeholder = "", addButtonText = "Add", removeButtonText = "Remove", emptyArrayFallback = [], preventEmpty = false, itemDescriptionFn, onBeforeAdd, onBeforeRemove, quickActions = [], } = config;
|
|
102
|
+
// Section heading
|
|
103
|
+
new Setting(containerEl).setName(name).setHeading();
|
|
104
|
+
// Description
|
|
105
|
+
if (desc) {
|
|
106
|
+
const descEl = containerEl.createDiv("setting-item-description");
|
|
107
|
+
descEl.setText(desc);
|
|
108
|
+
}
|
|
109
|
+
// Container for list items
|
|
110
|
+
const listContainer = containerEl.createDiv("settings-array-manager-list");
|
|
111
|
+
const render = () => {
|
|
112
|
+
var _a;
|
|
113
|
+
listContainer.empty();
|
|
114
|
+
const currentItems = (_a = this.settings[key]) !== null && _a !== void 0 ? _a : [];
|
|
115
|
+
for (const item of currentItems) {
|
|
116
|
+
const itemSetting = new Setting(listContainer).setName(String(item)).addButton((button) => button
|
|
117
|
+
.setButtonText(removeButtonText)
|
|
118
|
+
.setWarning()
|
|
119
|
+
.onClick(() => __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
let newItems = currentItems.filter((i) => i !== item);
|
|
121
|
+
// Apply custom logic before removal
|
|
122
|
+
if (onBeforeRemove) {
|
|
123
|
+
newItems = yield onBeforeRemove(item, currentItems);
|
|
124
|
+
}
|
|
125
|
+
// Prevent empty array if configured
|
|
126
|
+
if (preventEmpty && newItems.length === 0) {
|
|
127
|
+
newItems = Array.isArray(emptyArrayFallback)
|
|
128
|
+
? emptyArrayFallback
|
|
129
|
+
: [emptyArrayFallback];
|
|
130
|
+
}
|
|
131
|
+
yield this.updateSetting(key, newItems);
|
|
132
|
+
render();
|
|
133
|
+
})));
|
|
134
|
+
// Add custom description for each item if provided
|
|
135
|
+
if (itemDescriptionFn) {
|
|
136
|
+
itemSetting.setDesc(itemDescriptionFn(item));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
render();
|
|
141
|
+
// Add new item section
|
|
142
|
+
const inputId = `settings-array-manager-input-${key}`;
|
|
143
|
+
new Setting(containerEl)
|
|
144
|
+
.setName(`Add ${name.toLowerCase()}`)
|
|
145
|
+
.setDesc(`Enter a new value`)
|
|
146
|
+
.addText((text) => {
|
|
147
|
+
text.setPlaceholder(placeholder);
|
|
148
|
+
text.inputEl.id = inputId;
|
|
149
|
+
})
|
|
150
|
+
.addButton((button) => button
|
|
151
|
+
.setButtonText(addButtonText)
|
|
152
|
+
.setCta()
|
|
153
|
+
.onClick(() => __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
var _a;
|
|
155
|
+
const input = containerEl.querySelector(`#${inputId}`);
|
|
156
|
+
const newItem = input.value.trim();
|
|
157
|
+
if (!newItem) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const currentItems = (_a = this.settings[key]) !== null && _a !== void 0 ? _a : [];
|
|
161
|
+
let newItems = [...currentItems];
|
|
162
|
+
// Apply custom logic before adding
|
|
163
|
+
if (onBeforeAdd) {
|
|
164
|
+
newItems = yield onBeforeAdd(newItem, currentItems);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// Default behavior: add if not exists
|
|
168
|
+
if (!newItems.includes(newItem)) {
|
|
169
|
+
newItems.push(newItem);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
yield this.updateSetting(key, newItems);
|
|
173
|
+
input.value = "";
|
|
174
|
+
render();
|
|
175
|
+
})));
|
|
176
|
+
// Quick actions
|
|
177
|
+
for (const quickAction of quickActions) {
|
|
178
|
+
const currentItems = (_a = this.settings[key]) !== null && _a !== void 0 ? _a : [];
|
|
179
|
+
// Check condition if provided
|
|
180
|
+
if (quickAction.condition && !quickAction.condition(currentItems)) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
new Setting(containerEl)
|
|
184
|
+
.setName(quickAction.name)
|
|
185
|
+
.setDesc(quickAction.desc)
|
|
186
|
+
.addButton((button) => button.setButtonText(quickAction.buttonText).onClick(() => __awaiter(this, void 0, void 0, function* () {
|
|
187
|
+
var _a;
|
|
188
|
+
const currentItems = (_a = this.settings[key]) !== null && _a !== void 0 ? _a : [];
|
|
189
|
+
const newItems = yield quickAction.action(currentItems);
|
|
190
|
+
yield this.updateSetting(key, newItems);
|
|
191
|
+
render();
|
|
192
|
+
})));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Automatically detect the type from current value and create appropriate control
|
|
197
|
+
*/
|
|
198
|
+
auto(containerEl, config) {
|
|
199
|
+
const value = this.settings[config.key];
|
|
200
|
+
// Detect type from current value
|
|
201
|
+
if (typeof value === "boolean") {
|
|
202
|
+
this.addToggle(containerEl, config);
|
|
203
|
+
}
|
|
204
|
+
else if (typeof value === "number") {
|
|
205
|
+
this.addSlider(containerEl, config);
|
|
206
|
+
}
|
|
207
|
+
else if (typeof value === "string") {
|
|
208
|
+
this.addText(containerEl, config);
|
|
209
|
+
}
|
|
210
|
+
else if (Array.isArray(value)) {
|
|
211
|
+
this.addTextArray(containerEl, config);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
console.warn(`Unsupported value type for key ${config.key}: ${typeof value}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=settings-ui-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-ui-builder.js","sourceRoot":"","sources":["../src/settings-ui-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { Setting } from \"obsidian\";\nimport type { ZodObject, ZodRawShape, z } from \"zod\";\nimport type { SettingsStore } from \"./settings-store\";\n\ninterface BaseSettingConfig {\n\tkey: string;\n\tname: string;\n\tdesc: string;\n}\n\ninterface TextSettingConfig extends BaseSettingConfig {\n\tplaceholder?: string;\n}\n\ninterface SliderSettingConfig extends BaseSettingConfig {\n\tmin?: number;\n\tmax?: number;\n\tstep?: number;\n}\n\ninterface ArraySettingConfig extends BaseSettingConfig {\n\tplaceholder?: string;\n\tarrayDelimiter?: string;\n\tmultiline?: boolean;\n}\n\ninterface ArrayManagerConfig extends BaseSettingConfig {\n\tplaceholder?: string;\n\taddButtonText?: string;\n\tremoveButtonText?: string;\n\temptyArrayFallback?: unknown;\n\tpreventEmpty?: boolean;\n\titemDescriptionFn?: (item: unknown) => string;\n\tonBeforeAdd?: (newItem: unknown, currentItems: unknown[]) => unknown[] | Promise<unknown[]>;\n\tonBeforeRemove?: (\n\t\titemToRemove: unknown,\n\t\tcurrentItems: unknown[]\n\t) => unknown[] | Promise<unknown[]>;\n\tquickActions?: Array<{\n\t\tname: string;\n\t\tdesc: string;\n\t\tbuttonText: string;\n\t\tcondition?: (currentItems: unknown[]) => boolean;\n\t\taction: (currentItems: unknown[]) => unknown[] | Promise<unknown[]>;\n\t}>;\n}\n\nexport class SettingsUIBuilder<TSchema extends ZodObject<ZodRawShape>> {\n\tconstructor(private settingsStore: SettingsStore<TSchema>) {}\n\n\tprivate get settings(): z.infer<TSchema> {\n\t\treturn this.settingsStore.currentSettings;\n\t}\n\n\tprivate async updateSetting(key: keyof z.infer<TSchema>, value: unknown): Promise<void> {\n\t\tawait this.settingsStore.updateSettings(\n\t\t\t(s) =>\n\t\t\t\t({\n\t\t\t\t\t...s,\n\t\t\t\t\t[key]: value,\n\t\t\t\t}) as z.infer<TSchema>\n\t\t);\n\t}\n\n\taddToggle(containerEl: HTMLElement, config: BaseSettingConfig): void {\n\t\tconst { key, name, desc } = config;\n\t\tconst value = this.settings[key as keyof z.infer<TSchema>];\n\n\t\tnew Setting(containerEl)\n\t\t\t.setName(name)\n\t\t\t.setDesc(desc)\n\t\t\t.addToggle((toggle) =>\n\t\t\t\ttoggle.setValue(Boolean(value)).onChange(async (newValue) => {\n\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, newValue);\n\t\t\t\t})\n\t\t\t);\n\t}\n\n\taddSlider(containerEl: HTMLElement, config: SliderSettingConfig): void {\n\t\tconst { key, name, desc, min = 0, max = 100, step = 1 } = config;\n\t\tconst value = this.settings[key as keyof z.infer<TSchema>];\n\n\t\tnew Setting(containerEl)\n\t\t\t.setName(name)\n\t\t\t.setDesc(desc)\n\t\t\t.addSlider((slider) => {\n\t\t\t\tslider\n\t\t\t\t\t.setLimits(min, max, step)\n\t\t\t\t\t.setValue(Number(value))\n\t\t\t\t\t.setDynamicTooltip()\n\t\t\t\t\t.onChange(async (newValue) => {\n\t\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, newValue);\n\t\t\t\t\t});\n\n\t\t\t\treturn slider;\n\t\t\t});\n\t}\n\n\taddText(containerEl: HTMLElement, config: TextSettingConfig): void {\n\t\tconst { key, name, desc, placeholder = \"\" } = config;\n\t\tconst value = this.settings[key as keyof z.infer<TSchema>];\n\n\t\tnew Setting(containerEl)\n\t\t\t.setName(name)\n\t\t\t.setDesc(desc)\n\t\t\t.addText((text) =>\n\t\t\t\ttext\n\t\t\t\t\t.setPlaceholder(placeholder)\n\t\t\t\t\t.setValue(String(value ?? \"\"))\n\t\t\t\t\t.onChange(async (newValue) => {\n\t\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, newValue);\n\t\t\t\t\t})\n\t\t\t);\n\t}\n\n\taddTextArray(containerEl: HTMLElement, config: ArraySettingConfig): void {\n\t\tconst { key, name, desc, placeholder = \"\", arrayDelimiter = \", \", multiline = false } = config;\n\t\tconst value = this.settings[key as keyof z.infer<TSchema>] as string[];\n\n\t\tconst setting = new Setting(containerEl).setName(name).setDesc(desc);\n\n\t\tif (multiline) {\n\t\t\tsetting.addTextArea((text) => {\n\t\t\t\ttext.setPlaceholder(placeholder);\n\t\t\t\ttext.setValue(Array.isArray(value) ? value.join(\"\\n\") : \"\");\n\n\t\t\t\tconst commit = async (inputValue: string) => {\n\t\t\t\t\tconst items = inputValue\n\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t.map((s) => s.trim())\n\t\t\t\t\t\t.filter((s) => s.length > 0);\n\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, items);\n\t\t\t\t};\n\n\t\t\t\ttext.inputEl.addEventListener(\"blur\", () => void commit(text.inputEl.value));\n\t\t\t\ttext.inputEl.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n\t\t\t\t\tif (e.key === \"Enter\" && (e.ctrlKey || e.metaKey)) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tvoid commit(text.inputEl.value);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\ttext.inputEl.rows = 5;\n\t\t\t\ttext.inputEl.classList.add(\"settings-ui-builder-textarea\");\n\t\t\t});\n\t\t} else {\n\t\t\tsetting.addText((text) => {\n\t\t\t\ttext.setPlaceholder(placeholder);\n\t\t\t\ttext.setValue(Array.isArray(value) ? value.join(arrayDelimiter) : \"\");\n\t\t\t\ttext.onChange(async (inputValue) => {\n\t\t\t\t\tconst items = inputValue\n\t\t\t\t\t\t.split(\",\")\n\t\t\t\t\t\t.map((s) => s.trim())\n\t\t\t\t\t\t.filter((s) => s.length > 0);\n\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, items);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Advanced array manager with add/remove buttons for each item\n\t * Similar to the directory settings pattern\n\t */\n\taddArrayManager(containerEl: HTMLElement, config: ArrayManagerConfig): void {\n\t\tconst {\n\t\t\tkey,\n\t\t\tname,\n\t\t\tdesc,\n\t\t\tplaceholder = \"\",\n\t\t\taddButtonText = \"Add\",\n\t\t\tremoveButtonText = \"Remove\",\n\t\t\temptyArrayFallback = [],\n\t\t\tpreventEmpty = false,\n\t\t\titemDescriptionFn,\n\t\t\tonBeforeAdd,\n\t\t\tonBeforeRemove,\n\t\t\tquickActions = [],\n\t\t} = config;\n\n\t\t// Section heading\n\t\tnew Setting(containerEl).setName(name).setHeading();\n\n\t\t// Description\n\t\tif (desc) {\n\t\t\tconst descEl = containerEl.createDiv(\"setting-item-description\");\n\t\t\tdescEl.setText(desc);\n\t\t}\n\n\t\t// Container for list items\n\t\tconst listContainer = containerEl.createDiv(\"settings-array-manager-list\");\n\n\t\tconst render = () => {\n\t\t\tlistContainer.empty();\n\n\t\t\tconst currentItems = (this.settings[key as keyof z.infer<TSchema>] as unknown[]) ?? [];\n\n\t\t\tfor (const item of currentItems) {\n\t\t\t\tconst itemSetting = new Setting(listContainer).setName(String(item)).addButton((button) =>\n\t\t\t\t\tbutton\n\t\t\t\t\t\t.setButtonText(removeButtonText)\n\t\t\t\t\t\t.setWarning()\n\t\t\t\t\t\t.onClick(async () => {\n\t\t\t\t\t\t\tlet newItems = currentItems.filter((i) => i !== item);\n\n\t\t\t\t\t\t\t// Apply custom logic before removal\n\t\t\t\t\t\t\tif (onBeforeRemove) {\n\t\t\t\t\t\t\t\tnewItems = await onBeforeRemove(item, currentItems);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Prevent empty array if configured\n\t\t\t\t\t\t\tif (preventEmpty && newItems.length === 0) {\n\t\t\t\t\t\t\t\tnewItems = Array.isArray(emptyArrayFallback)\n\t\t\t\t\t\t\t\t\t? emptyArrayFallback\n\t\t\t\t\t\t\t\t\t: [emptyArrayFallback];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, newItems);\n\t\t\t\t\t\t\trender();\n\t\t\t\t\t\t})\n\t\t\t\t);\n\n\t\t\t\t// Add custom description for each item if provided\n\t\t\t\tif (itemDescriptionFn) {\n\t\t\t\t\titemSetting.setDesc(itemDescriptionFn(item));\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\trender();\n\n\t\t// Add new item section\n\t\tconst inputId = `settings-array-manager-input-${key}`;\n\t\tnew Setting(containerEl)\n\t\t\t.setName(`Add ${name.toLowerCase()}`)\n\t\t\t.setDesc(`Enter a new value`)\n\t\t\t.addText((text) => {\n\t\t\t\ttext.setPlaceholder(placeholder);\n\t\t\t\ttext.inputEl.id = inputId;\n\t\t\t})\n\t\t\t.addButton((button) =>\n\t\t\t\tbutton\n\t\t\t\t\t.setButtonText(addButtonText)\n\t\t\t\t\t.setCta()\n\t\t\t\t\t.onClick(async () => {\n\t\t\t\t\t\tconst input = containerEl.querySelector(`#${inputId}`) as HTMLInputElement;\n\t\t\t\t\t\tconst newItem = input.value.trim();\n\n\t\t\t\t\t\tif (!newItem) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst currentItems = (this.settings[key as keyof z.infer<TSchema>] as unknown[]) ?? [];\n\t\t\t\t\t\tlet newItems = [...currentItems];\n\n\t\t\t\t\t\t// Apply custom logic before adding\n\t\t\t\t\t\tif (onBeforeAdd) {\n\t\t\t\t\t\t\tnewItems = await onBeforeAdd(newItem, currentItems);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Default behavior: add if not exists\n\t\t\t\t\t\t\tif (!newItems.includes(newItem)) {\n\t\t\t\t\t\t\t\tnewItems.push(newItem);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, newItems);\n\t\t\t\t\t\tinput.value = \"\";\n\t\t\t\t\t\trender();\n\t\t\t\t\t})\n\t\t\t);\n\n\t\t// Quick actions\n\t\tfor (const quickAction of quickActions) {\n\t\t\tconst currentItems = (this.settings[key as keyof z.infer<TSchema>] as unknown[]) ?? [];\n\n\t\t\t// Check condition if provided\n\t\t\tif (quickAction.condition && !quickAction.condition(currentItems)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnew Setting(containerEl)\n\t\t\t\t.setName(quickAction.name)\n\t\t\t\t.setDesc(quickAction.desc)\n\t\t\t\t.addButton((button) =>\n\t\t\t\t\tbutton.setButtonText(quickAction.buttonText).onClick(async () => {\n\t\t\t\t\t\tconst currentItems = (this.settings[key as keyof z.infer<TSchema>] as unknown[]) ?? [];\n\t\t\t\t\t\tconst newItems = await quickAction.action(currentItems);\n\t\t\t\t\t\tawait this.updateSetting(key as keyof z.infer<TSchema>, newItems);\n\t\t\t\t\t\trender();\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Automatically detect the type from current value and create appropriate control\n\t */\n\tauto(\n\t\tcontainerEl: HTMLElement,\n\t\tconfig: TextSettingConfig & SliderSettingConfig & ArraySettingConfig\n\t): void {\n\t\tconst value = this.settings[config.key as keyof z.infer<TSchema>];\n\n\t\t// Detect type from current value\n\t\tif (typeof value === \"boolean\") {\n\t\t\tthis.addToggle(containerEl, config);\n\t\t} else if (typeof value === \"number\") {\n\t\t\tthis.addSlider(containerEl, config);\n\t\t} else if (typeof value === \"string\") {\n\t\t\tthis.addText(containerEl, config);\n\t\t} else if (Array.isArray(value)) {\n\t\t\tthis.addTextArray(containerEl, config);\n\t\t} else {\n\t\t\tconsole.warn(`Unsupported value type for key ${config.key}: ${typeof value}`);\n\t\t}\n\t}\n}\n"]}
|