@papu1337/builder 0.0.4 → 1.0.1

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.
Files changed (124) hide show
  1. package/dist/builder/BuilderView.svelte +158 -0
  2. package/dist/builder/BuilderView.svelte.d.ts +8 -0
  3. package/dist/builder/builder.vanilla.es.js +6514 -0
  4. package/dist/builder/builder.vanilla.umd.js +89 -0
  5. package/dist/builder/canvas/canvas.svelte +92 -0
  6. package/dist/builder/canvas/canvas.svelte.d.ts +17 -0
  7. package/dist/builder/canvas/styles.css +63 -0
  8. package/dist/builder/createBuilder.svelte.d.ts +9 -0
  9. package/dist/builder/createBuilder.svelte.js +17 -0
  10. package/dist/builder/index.d.ts +8 -0
  11. package/dist/builder/index.js +7 -0
  12. package/dist/builder/leftbar/leftBar.svelte +740 -0
  13. package/dist/builder/leftbar/leftBar.svelte.d.ts +8 -0
  14. package/dist/builder/leftbar/styles.css +152 -0
  15. package/dist/builder/pageMeta.svelte.d.ts +13 -0
  16. package/dist/builder/pageMeta.svelte.js +25 -0
  17. package/dist/builder/rightbar/rightBar.svelte +100 -0
  18. package/dist/builder/rightbar/rightBar.svelte.d.ts +10 -0
  19. package/dist/builder/rightbar/styles.css +167 -0
  20. package/dist/builder/topbar/TopBar.svelte +337 -0
  21. package/dist/builder/topbar/TopBar.svelte.d.ts +12 -0
  22. package/dist/builder/topbar/styles.css +123 -0
  23. package/dist/builder/viewport.svelte.d.ts +9 -0
  24. package/dist/builder/viewport.svelte.js +17 -0
  25. package/dist/elements/_shared/Arrow.svelte +58 -0
  26. package/dist/elements/_shared/Arrow.svelte.d.ts +11 -0
  27. package/dist/elements/_shared/GradientBorder.svelte +55 -0
  28. package/dist/elements/_shared/GradientBorder.svelte.d.ts +10 -0
  29. package/dist/elements/banner/bannerElement.svelte +120 -24
  30. package/dist/elements/banner/settings.d.ts +15 -3
  31. package/dist/elements/banner/settings.js +93 -8
  32. package/dist/elements/button/buttonElement.svelte +31 -21
  33. package/dist/elements/button/settings.d.ts +12 -9
  34. package/dist/elements/button/settings.js +21 -38
  35. package/dist/elements/globalSettings.js +5 -4
  36. package/dist/elements/howItWorks/howItWorksElement.svelte +221 -0
  37. package/dist/elements/howItWorks/howItWorksElement.svelte.d.ts +7 -0
  38. package/dist/elements/howItWorks/settings.d.ts +16 -0
  39. package/dist/elements/howItWorks/settings.js +70 -0
  40. package/dist/elements/steps/settings.d.ts +17 -0
  41. package/dist/elements/steps/settings.js +69 -0
  42. package/dist/elements/steps/stepsElement.svelte +220 -0
  43. package/dist/elements/steps/stepsElement.svelte.d.ts +7 -0
  44. package/dist/elements/terms/settings.d.ts +8 -5
  45. package/dist/elements/terms/settings.js +26 -33
  46. package/dist/elements/terms/termsElement.svelte +164 -79
  47. package/dist/elements/text/settings.d.ts +5 -3
  48. package/dist/elements/text/settings.js +22 -8
  49. package/dist/elements/text/textElement.svelte +25 -20
  50. package/dist/hooks/index.d.ts +1 -0
  51. package/dist/hooks/index.js +1 -0
  52. package/dist/hooks/useTranslation.svelte.d.ts +9 -0
  53. package/dist/hooks/useTranslation.svelte.js +10 -0
  54. package/dist/index.d.ts +3 -0
  55. package/dist/index.js +3 -0
  56. package/dist/renderer/BuilderRenderer.svelte +30 -2
  57. package/dist/renderer/registry.js +7 -13
  58. package/dist/renderer/renderer.vanilla.es.js +1395 -1218
  59. package/dist/renderer/renderer.vanilla.umd.js +64 -31
  60. package/dist/renderer/resolve.d.ts +1 -1
  61. package/dist/renderer/resolve.js +28 -14
  62. package/dist/renderer/types.d.ts +2 -0
  63. package/dist/service/element.action.svelte.d.ts +21 -0
  64. package/dist/service/element.action.svelte.js +125 -0
  65. package/dist/service/element.history.svelte.d.ts +8 -0
  66. package/dist/service/element.history.svelte.js +36 -0
  67. package/dist/service/element.io.svelte.d.ts +4 -0
  68. package/dist/service/element.io.svelte.js +232 -0
  69. package/dist/service/element.reader.svelte.d.ts +4 -0
  70. package/dist/service/element.reader.svelte.js +51 -0
  71. package/dist/service/element.translate.svelte.d.ts +12 -0
  72. package/dist/service/element.translate.svelte.js +81 -0
  73. package/dist/service/index.d.ts +5 -0
  74. package/dist/service/index.js +5 -0
  75. package/dist/service/types.d.ts +13 -0
  76. package/dist/service/types.js +1 -0
  77. package/dist/settings/base.svelte.d.ts +6 -1
  78. package/dist/settings/base.svelte.js +64 -22
  79. package/dist/settings/components/ColorSettings.svelte +174 -45
  80. package/dist/settings/components/ColorSettings.svelte.d.ts +3 -2
  81. package/dist/settings/components/ListSettings.svelte +11 -12
  82. package/dist/settings/components/NumberSettings.svelte +121 -24
  83. package/dist/settings/components/RepeaterSettings.svelte +145 -0
  84. package/dist/settings/components/RepeaterSettings.svelte.d.ts +14 -0
  85. package/dist/settings/components/SegmentSettings.svelte +85 -0
  86. package/dist/settings/components/SegmentSettings.svelte.d.ts +5 -0
  87. package/dist/settings/components/SelectSettings.svelte +6 -7
  88. package/dist/settings/components/SettingsGroup.svelte +13 -68
  89. package/dist/settings/components/SettingsRenderer.svelte +76 -0
  90. package/dist/settings/components/SettingsRenderer.svelte.d.ts +8 -0
  91. package/dist/settings/components/TextSettings.svelte +52 -2
  92. package/dist/settings/components/TranslatableSettings.svelte +16 -17
  93. package/dist/settings/components/UploadSettings.svelte +7 -8
  94. package/dist/settings/groups.d.ts +23 -7
  95. package/dist/settings/groups.js +48 -24
  96. package/dist/settings/implementation.svelte.js +4 -0
  97. package/dist/settings/index.d.ts +2 -0
  98. package/dist/settings/index.js +2 -0
  99. package/dist/settings/mode.svelte.d.ts +4 -0
  100. package/dist/settings/mode.svelte.js +4 -0
  101. package/dist/settings/repeater.svelte.d.ts +26 -0
  102. package/dist/settings/repeater.svelte.js +70 -0
  103. package/dist/settings/types.d.ts +28 -2
  104. package/package.json +11 -5
  105. package/dist/elements/auth/authElement.svelte +0 -115
  106. package/dist/elements/auth/authElement.svelte.d.ts +0 -7
  107. package/dist/elements/auth/settings.d.ts +0 -25
  108. package/dist/elements/auth/settings.js +0 -63
  109. package/dist/elements/badge/badgeElement.svelte +0 -48
  110. package/dist/elements/badge/badgeElement.svelte.d.ts +0 -7
  111. package/dist/elements/badge/settings.d.ts +0 -13
  112. package/dist/elements/badge/settings.js +0 -57
  113. package/dist/elements/cards/cardsElement.svelte +0 -136
  114. package/dist/elements/cards/cardsElement.svelte.d.ts +0 -7
  115. package/dist/elements/cards/settings.d.ts +0 -14
  116. package/dist/elements/cards/settings.js +0 -52
  117. package/dist/elements/divider/dividerElement.svelte +0 -34
  118. package/dist/elements/divider/dividerElement.svelte.d.ts +0 -7
  119. package/dist/elements/divider/settings.d.ts +0 -7
  120. package/dist/elements/divider/settings.js +0 -15
  121. package/dist/elements/products/productsElement.svelte +0 -283
  122. package/dist/elements/products/productsElement.svelte.d.ts +0 -7
  123. package/dist/elements/products/settings.d.ts +0 -16
  124. package/dist/elements/products/settings.js +0 -56
@@ -0,0 +1,36 @@
1
+ const MAX_HISTORY = 50;
2
+ let captureState;
3
+ let restoreState;
4
+ let undoStack = $state([]);
5
+ let redoStack = $state([]);
6
+ export function initHistory(capture, restore) {
7
+ captureState = capture;
8
+ restoreState = restore;
9
+ }
10
+ export function saveHistory() {
11
+ undoStack.push(captureState());
12
+ if (undoStack.length > MAX_HISTORY) {
13
+ undoStack.shift();
14
+ }
15
+ redoStack.length = 0;
16
+ }
17
+ export function undo() {
18
+ const snapshot = undoStack.pop();
19
+ if (!snapshot)
20
+ return;
21
+ redoStack.push(captureState());
22
+ restoreState(snapshot);
23
+ }
24
+ export function redo() {
25
+ const snapshot = redoStack.pop();
26
+ if (!snapshot)
27
+ return;
28
+ undoStack.push(captureState());
29
+ restoreState(snapshot);
30
+ }
31
+ export function canUndo() {
32
+ return undoStack.length > 0;
33
+ }
34
+ export function canRedo() {
35
+ return redoStack.length > 0;
36
+ }
@@ -0,0 +1,4 @@
1
+ export declare function exportState(): string;
2
+ export declare function importState(json: string): void;
3
+ export declare function exportTranslations(): string;
4
+ export declare function importTranslations(json: string): void;
@@ -0,0 +1,232 @@
1
+ import { Setting, Settings } from "../settings/base.svelte";
2
+ import { RepeaterSetting } from "../settings/repeater.svelte";
3
+ import { saveHistory } from "./element.history.svelte";
4
+ import { elements } from "./element.reader.svelte";
5
+ import { ComponentsInstance, GLOBAL_KEY, cloneEntry, trackSettings, } from "./element.action.svelte";
6
+ import { languages } from "../hooks/useTranslation.svelte";
7
+ function collectValues(settings) {
8
+ const result = {};
9
+ for (const key in settings.entries) {
10
+ const item = settings.entries[key];
11
+ if (item instanceof Settings) {
12
+ result[key] = collectValues(item);
13
+ }
14
+ else if (item instanceof RepeaterSetting) {
15
+ result[key] = item.items.map((child) => collectValues(child));
16
+ }
17
+ else {
18
+ result[key] = item.value;
19
+ }
20
+ }
21
+ return result;
22
+ }
23
+ function applyValues(settings, values) {
24
+ for (const key in settings.entries) {
25
+ const item = settings.entries[key];
26
+ if (item instanceof Settings) {
27
+ const nested = values[key];
28
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
29
+ applyValues(item, nested);
30
+ }
31
+ }
32
+ else if (item instanceof RepeaterSetting) {
33
+ const list = values[key];
34
+ if (Array.isArray(list)) {
35
+ item.items = list.map((entryValues, index) => {
36
+ const created = item.factory(index);
37
+ if (entryValues && typeof entryValues === "object") {
38
+ applyValues(created, entryValues);
39
+ }
40
+ return created;
41
+ });
42
+ }
43
+ }
44
+ else if (key in values) {
45
+ const setting = item;
46
+ if (setting.isTranslatable && typeof values[key] === "string") {
47
+ setting.value = { en: values[key] };
48
+ }
49
+ else {
50
+ setting.value = values[key];
51
+ }
52
+ }
53
+ }
54
+ }
55
+ function collectMobile(settings) {
56
+ const result = {};
57
+ for (const key in settings.entries) {
58
+ const item = settings.entries[key];
59
+ if (item instanceof Settings) {
60
+ const nested = collectMobile(item);
61
+ if (Object.keys(nested).length > 0)
62
+ result[key] = nested;
63
+ }
64
+ else if (item instanceof RepeaterSetting) {
65
+ const arr = item.items.map((child) => collectMobile(child));
66
+ if (arr.some((entry) => Object.keys(entry).length > 0))
67
+ result[key] = arr;
68
+ }
69
+ else {
70
+ const setting = item;
71
+ if (setting.mobileValue !== undefined)
72
+ result[key] = setting.mobileValue;
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+ function applyMobile(settings, values) {
78
+ for (const key in settings.entries) {
79
+ const item = settings.entries[key];
80
+ if (item instanceof Settings) {
81
+ const nested = values[key];
82
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
83
+ applyMobile(item, nested);
84
+ }
85
+ }
86
+ else if (item instanceof RepeaterSetting) {
87
+ const arr = values[key];
88
+ if (Array.isArray(arr)) {
89
+ item.items.forEach((child, index) => {
90
+ const nested = arr[index];
91
+ if (nested && typeof nested === "object") {
92
+ applyMobile(child, nested);
93
+ }
94
+ });
95
+ }
96
+ }
97
+ else if (key in values) {
98
+ item.mobileValue = values[key];
99
+ }
100
+ }
101
+ }
102
+ export function exportState() {
103
+ const globalEntry = ComponentsInstance.get(GLOBAL_KEY);
104
+ const globalSettings = globalEntry ? collectValues(globalEntry.settings) : {};
105
+ const exported = [];
106
+ for (const [id, entry] of ComponentsInstance) {
107
+ if (id === GLOBAL_KEY)
108
+ continue;
109
+ const mobileSettings = collectMobile(entry.settings);
110
+ exported.push({
111
+ name: `${entry.name}`,
112
+ settings: collectValues(entry.settings),
113
+ ...(Object.keys(mobileSettings).length > 0 ? { mobileSettings } : {}),
114
+ });
115
+ }
116
+ const state = { global: globalSettings, components: exported };
117
+ return JSON.stringify(state, null, 2);
118
+ }
119
+ export function importState(json) {
120
+ const state = JSON.parse(json);
121
+ saveHistory();
122
+ const globalEntry = ComponentsInstance.get(GLOBAL_KEY);
123
+ if (globalEntry && state.global) {
124
+ applyValues(globalEntry.settings, state.global);
125
+ trackSettings(globalEntry);
126
+ }
127
+ for (const id of [...ComponentsInstance.keys()]) {
128
+ if (id !== GLOBAL_KEY)
129
+ ComponentsInstance.delete(id);
130
+ }
131
+ for (const item of state.components) {
132
+ const template = elements.find((e) => e.name === item.name);
133
+ if (!template)
134
+ continue;
135
+ const instance = cloneEntry(template);
136
+ instance.id = `${template.name}-${crypto.randomUUID()}`;
137
+ applyValues(instance.settings, item.settings);
138
+ if (item.mobileSettings)
139
+ applyMobile(instance.settings, item.mobileSettings);
140
+ ComponentsInstance.set(instance.id, instance);
141
+ trackSettings(instance);
142
+ }
143
+ }
144
+ export function exportTranslations() {
145
+ const dictionary = {};
146
+ const collectCompTrans = (settings) => {
147
+ const result = {};
148
+ const walk = (s) => {
149
+ for (const key in s.entries) {
150
+ const item = s.entries[key];
151
+ if (item instanceof Settings) {
152
+ walk(item);
153
+ }
154
+ else if (item instanceof RepeaterSetting) {
155
+ item.items.forEach(walk);
156
+ }
157
+ else {
158
+ const setting = item;
159
+ if (setting.isTranslatable) {
160
+ const val = setting.value;
161
+ const langs = {};
162
+ for (const lang of languages) {
163
+ langs[lang.code] =
164
+ val[lang.code] || (lang.code === "en" ? val["en"] : "");
165
+ }
166
+ result[key] = langs;
167
+ }
168
+ }
169
+ }
170
+ };
171
+ walk(settings);
172
+ return result;
173
+ };
174
+ const globalEntry = ComponentsInstance.get(GLOBAL_KEY);
175
+ if (globalEntry) {
176
+ const tr = collectCompTrans(globalEntry.settings);
177
+ if (Object.keys(tr).length > 0)
178
+ dictionary[`Global-1`] = tr;
179
+ }
180
+ const counts = {};
181
+ for (const [id, entry] of ComponentsInstance) {
182
+ if (id === GLOBAL_KEY)
183
+ continue;
184
+ counts[entry.name] = (counts[entry.name] || 0) + 1;
185
+ const compId = `${entry.name}-${counts[entry.name]}`;
186
+ const tr = collectCompTrans(entry.settings);
187
+ if (Object.keys(tr).length > 0)
188
+ dictionary[compId] = tr;
189
+ }
190
+ return JSON.stringify(dictionary, null, 2);
191
+ }
192
+ export function importTranslations(json) {
193
+ const dictionary = JSON.parse(json);
194
+ saveHistory();
195
+ const applyCompTrans = (settings, compTrans) => {
196
+ const walk = (s) => {
197
+ for (const key in s.entries) {
198
+ const item = s.entries[key];
199
+ if (item instanceof Settings) {
200
+ walk(item);
201
+ }
202
+ else if (item instanceof RepeaterSetting) {
203
+ item.items.forEach(walk);
204
+ }
205
+ else {
206
+ const setting = item;
207
+ if (setting.isTranslatable && compTrans[key]) {
208
+ const val = setting.value;
209
+ setting.value = { ...val, ...compTrans[key] };
210
+ }
211
+ }
212
+ }
213
+ };
214
+ walk(settings);
215
+ };
216
+ const globalEntry = ComponentsInstance.get(GLOBAL_KEY);
217
+ if (globalEntry && dictionary[`Global-1`]) {
218
+ applyCompTrans(globalEntry.settings, dictionary[`Global-1`]);
219
+ trackSettings(globalEntry);
220
+ }
221
+ const counts = {};
222
+ for (const [id, entry] of ComponentsInstance) {
223
+ if (id !== GLOBAL_KEY) {
224
+ counts[entry.name] = (counts[entry.name] || 0) + 1;
225
+ const compId = `${entry.name}-${counts[entry.name]}`;
226
+ if (dictionary[compId]) {
227
+ applyCompTrans(entry.settings, dictionary[compId]);
228
+ trackSettings(entry);
229
+ }
230
+ }
231
+ }
232
+ }
@@ -0,0 +1,4 @@
1
+ import { Settings, type SettingMap } from '../settings';
2
+ import type { ElementEntry } from './types';
3
+ export declare function discoverGlobalSettings(): Settings<SettingMap>;
4
+ export declare const elements: ElementEntry[];
@@ -0,0 +1,51 @@
1
+ import { Settings } from '../settings';
2
+ const settingsModules = import.meta.glob('../elements/**/settings.ts', {
3
+ eager: true
4
+ });
5
+ const GlobalSettingModule = import.meta.glob('../elements/globalSettings.ts', {
6
+ eager: true
7
+ });
8
+ const componentModules = import.meta.glob('../elements/*/*.svelte', {
9
+ eager: true
10
+ });
11
+ function findSettings(mod) {
12
+ for (const value of Object.values(mod)) {
13
+ if (value instanceof Settings)
14
+ return value;
15
+ }
16
+ }
17
+ function extractFolderName(path) {
18
+ return path.split('/').at(-2);
19
+ }
20
+ function findComponentModule(folderName) {
21
+ const path = Object.keys(componentModules).find((p) => p.includes(`/elements/${folderName}/`));
22
+ return path ? componentModules[path] : undefined;
23
+ }
24
+ function discoverElements() {
25
+ const entries = [];
26
+ for (const [path, mod] of Object.entries(settingsModules)) {
27
+ const folderName = extractFolderName(path);
28
+ const settings = findSettings(mod);
29
+ const componentModule = findComponentModule(folderName);
30
+ if (settings && componentModule) {
31
+ entries.push({
32
+ id: crypto.randomUUID(),
33
+ name: folderName,
34
+ settings,
35
+ component: componentModule.default
36
+ });
37
+ }
38
+ }
39
+ return entries;
40
+ }
41
+ export function discoverGlobalSettings() {
42
+ const allEntries = {};
43
+ for (const mod of Object.values(GlobalSettingModule)) {
44
+ const settings = findSettings(mod);
45
+ if (settings) {
46
+ Object.assign(allEntries, settings.entries);
47
+ }
48
+ }
49
+ return new Settings('Global', allEntries);
50
+ }
51
+ export const elements = $state(discoverElements());
@@ -0,0 +1,12 @@
1
+ export declare const translating: {
2
+ active: boolean;
3
+ };
4
+ type Translator = (text: string, targetLang: string) => Promise<string>;
5
+ export declare function setTranslator(fn: Translator | null): void;
6
+ export interface TranslateResult {
7
+ hasSource: boolean;
8
+ translated: number;
9
+ failed: number;
10
+ }
11
+ export declare function translateAll(): Promise<TranslateResult>;
12
+ export {};
@@ -0,0 +1,81 @@
1
+ import { Setting, Settings } from '../settings/base.svelte';
2
+ import { RepeaterSetting } from '../settings/repeater.svelte';
3
+ import { languages } from '../hooks/useTranslation.svelte';
4
+ import { ComponentsInstance } from './element.action.svelte';
5
+ import { saveHistory } from './element.history.svelte';
6
+ const SOURCE_LOCALE = 'en';
7
+ const REQUEST_TIMEOUT_MS = 10000;
8
+ export const translating = $state({ active: false });
9
+ let translator = null;
10
+ export function setTranslator(fn) {
11
+ translator = fn;
12
+ }
13
+ function collectTranslatable(settings, out) {
14
+ for (const key in settings.entries) {
15
+ const item = settings.entries[key];
16
+ if (item instanceof Settings) {
17
+ collectTranslatable(item, out);
18
+ }
19
+ else if (item instanceof RepeaterSetting) {
20
+ item.items.forEach((child) => collectTranslatable(child, out));
21
+ }
22
+ else {
23
+ const setting = item;
24
+ if (setting.isTranslatable)
25
+ out.push(setting);
26
+ }
27
+ }
28
+ }
29
+ async function translateText(text, target) {
30
+ if (translator)
31
+ return translator(text, target);
32
+ const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${SOURCE_LOCALE}&tl=${encodeURIComponent(target)}&dt=t&q=${encodeURIComponent(text)}`;
33
+ const response = await fetch(url, { signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
34
+ if (!response.ok)
35
+ throw new Error(`Translation request failed (${response.status})`);
36
+ const data = await response.json();
37
+ if (!Array.isArray(data) || !Array.isArray(data[0])) {
38
+ throw new Error('Unexpected translation response');
39
+ }
40
+ return data[0]
41
+ .map((segment) => (Array.isArray(segment) ? String(segment[0] ?? '') : ''))
42
+ .join('');
43
+ }
44
+ export async function translateAll() {
45
+ const targets = languages.filter((lang) => lang.code !== SOURCE_LOCALE).map((lang) => lang.code);
46
+ const leaves = [];
47
+ for (const entry of ComponentsInstance.values())
48
+ collectTranslatable(entry.settings, leaves);
49
+ const jobs = [];
50
+ let hasSource = false;
51
+ for (const setting of leaves) {
52
+ const source = setting.value?.[SOURCE_LOCALE];
53
+ if (typeof source !== 'string' || !source.trim())
54
+ continue;
55
+ hasSource = true;
56
+ for (const target of targets)
57
+ jobs.push({ setting, target, text: source });
58
+ }
59
+ if (!hasSource)
60
+ return { hasSource: false, translated: 0, failed: 0 };
61
+ saveHistory();
62
+ translating.active = true;
63
+ let translated = 0;
64
+ let failed = 0;
65
+ try {
66
+ for (const job of jobs) {
67
+ try {
68
+ const result = await translateText(job.text, job.target);
69
+ job.setting.value = { ...job.setting.value, [job.target]: result };
70
+ translated++;
71
+ }
72
+ catch {
73
+ failed++;
74
+ }
75
+ }
76
+ }
77
+ finally {
78
+ translating.active = false;
79
+ }
80
+ return { hasSource: true, translated, failed };
81
+ }
@@ -0,0 +1,5 @@
1
+ export * from './element.reader.svelte';
2
+ export * from './element.action.svelte';
3
+ export * from './element.io.svelte';
4
+ export * from './element.translate.svelte';
5
+ export * from './types';
@@ -0,0 +1,5 @@
1
+ export * from './element.reader.svelte';
2
+ export * from './element.action.svelte';
3
+ export * from './element.io.svelte';
4
+ export * from './element.translate.svelte';
5
+ export * from './types';
@@ -0,0 +1,13 @@
1
+ import { Settings, type SettingMap } from '../settings';
2
+ import type { Component } from 'svelte';
3
+ export type { ExportedEntry, ExportedState } from '../renderer/types';
4
+ export interface ElementEntry {
5
+ id: string;
6
+ name: string;
7
+ settings: Settings<SettingMap>;
8
+ component: Component<Record<string, unknown>> | null;
9
+ }
10
+ export type SettingsModule = Record<string, unknown>;
11
+ export type ComponentModule = {
12
+ default: Component<Record<string, unknown>>;
13
+ };
@@ -0,0 +1 @@
1
+ import { Settings } from '../settings';
@@ -2,9 +2,11 @@ import type { Component } from 'svelte';
2
2
  import type { BaseSettingProps, SettingMap, SettingComponent } from './types.js';
3
3
  export declare abstract class Setting<V, E extends Record<string, unknown> = Record<string, unknown>> {
4
4
  value: V;
5
+ mobileValue: V | undefined;
5
6
  readonly title: string;
6
7
  readonly extra: E;
7
8
  readonly isTranslatable: boolean;
9
+ lastChangedMobile: boolean;
8
10
  onValueChange: ((oldValue: V, newValue: V) => void) | null;
9
11
  abstract readonly component: Component<BaseSettingProps<V> & E>;
10
12
  constructor(options: {
@@ -12,11 +14,14 @@ export declare abstract class Setting<V, E extends Record<string, unknown> = Rec
12
14
  defaultValue: V;
13
15
  extra?: E;
14
16
  });
17
+ get effectiveValue(): V;
18
+ private previewing;
15
19
  private previewOrigin;
20
+ private resetMobile;
16
21
  getProps(): BaseSettingProps<V> & E;
17
22
  }
18
23
  type SettingsValues<T extends SettingMap> = {
19
- [K in keyof T]: T[K] extends SettingComponent ? T[K]['value'] : never;
24
+ [K in keyof T]: T[K] extends Settings<infer U> ? SettingsValues<U> : T[K] extends SettingComponent ? T[K]['value'] : never;
20
25
  };
21
26
  export type SettingsEntry = Setting<unknown, Record<string, unknown>> | Settings<SettingMap>;
22
27
  export declare function isSettingsGroup(entry: SettingsEntry): entry is Settings<SettingMap>;
@@ -1,31 +1,64 @@
1
- import { locale } from '../../hooks/useTranslation.svelte.js';
1
+ import { locale } from '../hooks/useTranslation.svelte.js';
2
+ import { settingsMode } from './mode.svelte.js';
2
3
  export class Setting {
3
4
  value = $state();
5
+ mobileValue = $state(undefined);
4
6
  title;
5
7
  extra;
6
8
  isTranslatable = false;
9
+ lastChangedMobile = false;
7
10
  onValueChange = null;
8
11
  constructor(options) {
9
12
  this.title = options.title;
10
13
  this.value = options.defaultValue;
11
14
  this.extra = (options.extra ?? {});
12
15
  }
13
- previewOrigin = null;
16
+ get effectiveValue() {
17
+ return settingsMode.device === 'mobile' && this.mobileValue !== undefined
18
+ ? this.mobileValue
19
+ : this.value;
20
+ }
21
+ previewing = false;
22
+ previewOrigin = undefined;
23
+ resetMobile() {
24
+ const oldValue = this.mobileValue;
25
+ this.lastChangedMobile = true;
26
+ this.mobileValue = undefined;
27
+ this.onValueChange?.(oldValue, this.value);
28
+ }
14
29
  getProps() {
30
+ const mobile = settingsMode.device === 'mobile';
31
+ const current = mobile ? (this.mobileValue ?? this.value) : this.value;
15
32
  return {
16
- value: this.value,
33
+ value: current,
17
34
  title: this.title,
35
+ isMobile: mobile,
36
+ overridden: mobile && this.mobileValue !== undefined,
37
+ onreset: mobile ? () => this.resetMobile() : undefined,
18
38
  onchange: (v) => {
19
- const oldValue = this.previewOrigin ?? this.value;
20
- this.previewOrigin = null;
21
- this.value = v;
22
- this.onValueChange?.(oldValue, v);
39
+ const rawOld = this.previewing
40
+ ? this.previewOrigin
41
+ : mobile
42
+ ? this.mobileValue
43
+ : this.value;
44
+ this.previewing = false;
45
+ this.previewOrigin = undefined;
46
+ this.lastChangedMobile = mobile;
47
+ if (mobile)
48
+ this.mobileValue = v;
49
+ else
50
+ this.value = v;
51
+ this.onValueChange?.(rawOld, v);
23
52
  },
24
53
  onpreview: (v) => {
25
- if (this.previewOrigin === null) {
26
- this.previewOrigin = this.value;
54
+ if (!this.previewing) {
55
+ this.previewing = true;
56
+ this.previewOrigin = mobile ? this.mobileValue : this.value;
27
57
  }
28
- this.value = v;
58
+ if (mobile)
59
+ this.mobileValue = v;
60
+ else
61
+ this.value = v;
29
62
  },
30
63
  ...this.extra
31
64
  };
@@ -48,19 +81,27 @@ export class Settings {
48
81
  if (entry instanceof Settings) {
49
82
  clonedEntries[key] = entry.clone();
50
83
  }
84
+ else if (typeof entry.clone === 'function') {
85
+ clonedEntries[key] = entry.clone();
86
+ }
51
87
  else {
52
88
  const setting = entry;
53
- const defaultValue = Array.isArray(setting.value)
54
- ? structuredClone(setting.value)
55
- : typeof setting.value === 'object' && setting.value !== null
56
- ? { ...setting.value }
57
- : setting.value;
89
+ const defaultValue = typeof setting.value === 'object' && setting.value !== null
90
+ ? JSON.parse(JSON.stringify(setting.value))
91
+ : setting.value;
58
92
  const Ctor = setting.constructor;
59
- clonedEntries[key] = new Ctor({
93
+ const clonedSetting = new Ctor({
60
94
  title: setting.title,
61
95
  defaultValue,
62
96
  extra: setting.extra
63
97
  });
98
+ if (setting.mobileValue !== undefined) {
99
+ clonedSetting.mobileValue =
100
+ typeof setting.mobileValue === 'object' && setting.mobileValue !== null
101
+ ? JSON.parse(JSON.stringify(setting.mobileValue))
102
+ : setting.mobileValue;
103
+ }
104
+ clonedEntries[key] = clonedSetting;
64
105
  }
65
106
  }
66
107
  return new Settings(this.title, clonedEntries);
@@ -70,19 +111,20 @@ export class Settings {
70
111
  for (const key in this.entries) {
71
112
  const entry = this.entries[key];
72
113
  if (entry instanceof Settings) {
73
- const nested = entry.values;
74
- for (const nk in nested) {
75
- result[nk] = nested[nk];
76
- }
114
+ result[key] = entry.values;
115
+ }
116
+ else if (typeof entry.resolvedValues === 'function') {
117
+ result[key] = entry.resolvedValues();
77
118
  }
78
119
  else {
79
120
  const setting = entry;
121
+ const effective = setting.effectiveValue;
80
122
  if (setting.isTranslatable) {
81
- const map = setting.value;
123
+ const map = effective;
82
124
  result[key] = map[locale.current] ?? map['en'] ?? '';
83
125
  }
84
126
  else {
85
- result[key] = setting.value;
127
+ result[key] = effective;
86
128
  }
87
129
  }
88
130
  }