@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 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
@@ -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":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AA+CnC,MAAM,OAAO,iBAAiB;IAC7B,YAAoB,aAAqC;QAArC,kBAAa,GAAb,aAAa,CAAwB;IAAG,CAAC;IAE7D,IAAY,QAAQ;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC;IAC3C,CAAC;IAEa,aAAa,CAAC,GAA2B,EAAE,KAAc;;YACtE,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CACtC,CAAC,CAAC,EAAE,EAAE,CACL,iCACI,CAAC,KACJ,CAAC,GAAG,CAAC,EAAE,KAAK,IACS,CACvB,CAAC;QACH,CAAC;KAAA;IAED,SAAS,CAAC,WAAwB,EAAE,MAAyB;QAC5D,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAC,CAAC;QAE3D,IAAI,OAAO,CAAC,WAAW,CAAC;aACtB,OAAO,CAAC,IAAI,CAAC;aACb,OAAO,CAAC,IAAI,CAAC;aACb,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CACrB,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAO,QAAQ,EAAE,EAAE;YAC3D,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,QAAQ,CAAC,CAAC;QACnE,CAAC,CAAA,CAAC,CACF,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,WAAwB,EAAE,MAA2B;QAC9D,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAC,CAAC;QAE3D,IAAI,OAAO,CAAC,WAAW,CAAC;aACtB,OAAO,CAAC,IAAI,CAAC;aACb,OAAO,CAAC,IAAI,CAAC;aACb,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;YACrB,MAAM;iBACJ,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC;iBACzB,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;iBACvB,iBAAiB,EAAE;iBACnB,QAAQ,CAAC,CAAO,QAAQ,EAAE,EAAE;gBAC5B,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,QAAQ,CAAC,CAAC;YACnE,CAAC,CAAA,CAAC,CAAC;YAEJ,OAAO,MAAM,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,WAAwB,EAAE,MAAyB;QAC1D,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAC,CAAC;QAE3D,IAAI,OAAO,CAAC,WAAW,CAAC;aACtB,OAAO,CAAC,IAAI,CAAC;aACb,OAAO,CAAC,IAAI,CAAC;aACb,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACjB,IAAI;aACF,cAAc,CAAC,WAAW,CAAC;aAC3B,QAAQ,CAAC,MAAM,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC,CAAC;aAC7B,QAAQ,CAAC,CAAO,QAAQ,EAAE,EAAE;YAC5B,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,QAAQ,CAAC,CAAC;QACnE,CAAC,CAAA,CAAC,CACH,CAAC;IACJ,CAAC;IAED,YAAY,CAAC,WAAwB,EAAE,MAA0B;QAChE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,GAAG,EAAE,EAAE,cAAc,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC;QAC/F,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAa,CAAC;QAEvE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAErE,IAAI,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE;gBAC5B,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;gBACjC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAE5D,MAAM,MAAM,GAAG,CAAO,UAAkB,EAAE,EAAE;oBAC3C,MAAM,KAAK,GAAG,UAAU;yBACtB,KAAK,CAAC,IAAI,CAAC;yBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;yBACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBAC9B,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,KAAK,CAAC,CAAC;gBAChE,CAAC,CAAA,CAAC;gBAEF,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC7E,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAgB,EAAE,EAAE;oBAC7D,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;wBACnD,CAAC,CAAC,cAAc,EAAE,CAAC;wBACnB,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oBACjC,CAAC;gBACF,CAAC,CAAC,CAAC;gBAEH,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;gBACtB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;QACJ,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBACxB,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;gBACjC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACtE,IAAI,CAAC,QAAQ,CAAC,CAAO,UAAU,EAAE,EAAE;oBAClC,MAAM,KAAK,GAAG,UAAU;yBACtB,KAAK,CAAC,GAAG,CAAC;yBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;yBACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBAC9B,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,KAAK,CAAC,CAAC;gBAChE,CAAC,CAAA,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,WAAwB,EAAE,MAA0B;;QACnE,MAAM,EACL,GAAG,EACH,IAAI,EACJ,IAAI,EACJ,WAAW,GAAG,EAAE,EAChB,aAAa,GAAG,KAAK,EACrB,gBAAgB,GAAG,QAAQ,EAC3B,kBAAkB,GAAG,EAAE,EACvB,YAAY,GAAG,KAAK,EACpB,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,YAAY,GAAG,EAAE,GACjB,GAAG,MAAM,CAAC;QAEX,kBAAkB;QAClB,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;QAEpD,cAAc;QACd,IAAI,IAAI,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;YACjE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QAED,2BAA2B;QAC3B,MAAM,aAAa,GAAG,WAAW,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;QAE3E,MAAM,MAAM,GAAG,GAAG,EAAE;;YACnB,aAAa,CAAC,KAAK,EAAE,CAAC;YAEtB,MAAM,YAAY,GAAG,MAAC,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAe,mCAAI,EAAE,CAAC;YAEvF,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;gBACjC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CACzF,MAAM;qBACJ,aAAa,CAAC,gBAAgB,CAAC;qBAC/B,UAAU,EAAE;qBACZ,OAAO,CAAC,GAAS,EAAE;oBACnB,IAAI,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;oBAEtD,oCAAoC;oBACpC,IAAI,cAAc,EAAE,CAAC;wBACpB,QAAQ,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;oBACrD,CAAC;oBAED,oCAAoC;oBACpC,IAAI,YAAY,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC3C,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;4BAC3C,CAAC,CAAC,kBAAkB;4BACpB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;oBACzB,CAAC;oBAED,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,QAAQ,CAAC,CAAC;oBAClE,MAAM,EAAE,CAAC;gBACV,CAAC,CAAA,CAAC,CACH,CAAC;gBAEF,mDAAmD;gBACnD,IAAI,iBAAiB,EAAE,CAAC;oBACvB,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC9C,CAAC;YACF,CAAC;QACF,CAAC,CAAC;QAEF,MAAM,EAAE,CAAC;QAET,uBAAuB;QACvB,MAAM,OAAO,GAAG,gCAAgC,GAAG,EAAE,CAAC;QACtD,IAAI,OAAO,CAAC,WAAW,CAAC;aACtB,OAAO,CAAC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;aACpC,OAAO,CAAC,mBAAmB,CAAC;aAC5B,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACjB,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;YACjC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC;QAC3B,CAAC,CAAC;aACD,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CACrB,MAAM;aACJ,aAAa,CAAC,aAAa,CAAC;aAC5B,MAAM,EAAE;aACR,OAAO,CAAC,GAAS,EAAE;;YACnB,MAAM,KAAK,GAAG,WAAW,CAAC,aAAa,CAAC,IAAI,OAAO,EAAE,CAAqB,CAAC;YAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO;YACR,CAAC;YAED,MAAM,YAAY,GAAG,MAAC,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAe,mCAAI,EAAE,CAAC;YACvF,IAAI,QAAQ,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC;YAEjC,mCAAmC;YACnC,IAAI,WAAW,EAAE,CAAC;gBACjB,QAAQ,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACP,sCAAsC;gBACtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBACjC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACxB,CAAC;YACF,CAAC;YAED,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,QAAQ,CAAC,CAAC;YAClE,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;YACjB,MAAM,EAAE,CAAC;QACV,CAAC,CAAA,CAAC,CACH,CAAC;QAEH,gBAAgB;QAChB,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;YACxC,MAAM,YAAY,GAAG,MAAC,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAe,mCAAI,EAAE,CAAC;YAEvF,8BAA8B;YAC9B,IAAI,WAAW,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;gBACnE,SAAS;YACV,CAAC;YAED,IAAI,OAAO,CAAC,WAAW,CAAC;iBACtB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;iBACzB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC;iBACzB,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CACrB,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,GAAS,EAAE;;gBAC/D,MAAM,YAAY,GAAG,MAAC,IAAI,CAAC,QAAQ,CAAC,GAA6B,CAAe,mCAAI,EAAE,CAAC;gBACvF,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;gBACxD,MAAM,IAAI,CAAC,aAAa,CAAC,GAA6B,EAAE,QAAQ,CAAC,CAAC;gBAClE,MAAM,EAAE,CAAC;YACV,CAAC,CAAA,CAAC,CACF,CAAC;QACJ,CAAC;IACF,CAAC;IAED;;OAEG;IACH,IAAI,CACH,WAAwB,EACxB,MAAoE;QAEpE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAA6B,CAAC,CAAC;QAElE,iCAAiC;QACjC,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,kCAAkC,MAAM,CAAC,GAAG,KAAK,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;IACF,CAAC;CACD","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real1ty-obsidian-plugins/utils",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Shared utilities for Obsidian plugins",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",