@kustomizer/visual-editor 0.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.
|
@@ -0,0 +1,2235 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { InjectionToken, Type, EnvironmentProviders, OnInit, OnDestroy } from '@angular/core';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
import * as _ngrx_store from '@ngrx/store';
|
|
5
|
+
import * as _kustomizer_visual_editor from '@kustomizer/visual-editor';
|
|
6
|
+
import { SafeHtml } from '@angular/platform-browser';
|
|
7
|
+
import { Session, User, SupabaseClient } from '@supabase/supabase-js';
|
|
8
|
+
import { CanActivateFn } from '@angular/router';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Navigation target for the visual editor
|
|
12
|
+
*/
|
|
13
|
+
type VisualEditorNavigationTarget = {
|
|
14
|
+
type: 'page-list';
|
|
15
|
+
} | {
|
|
16
|
+
type: 'page-edit';
|
|
17
|
+
pageId: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'page-preview';
|
|
20
|
+
pageId: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Confirmation dialog options
|
|
24
|
+
*/
|
|
25
|
+
interface ConfirmDialogOptions {
|
|
26
|
+
title: string;
|
|
27
|
+
message: string;
|
|
28
|
+
confirmText?: string;
|
|
29
|
+
cancelText?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Abstract navigation service that consumers can implement
|
|
33
|
+
* to customize how the visual editor navigates between views
|
|
34
|
+
*/
|
|
35
|
+
declare abstract class VisualEditorNavigation {
|
|
36
|
+
/**
|
|
37
|
+
* Navigate to a target within the editor context
|
|
38
|
+
*/
|
|
39
|
+
abstract navigate(target: VisualEditorNavigationTarget): void;
|
|
40
|
+
/**
|
|
41
|
+
* Show a confirmation dialog
|
|
42
|
+
* Returns Observable<boolean> to support async dialogs (e.g., Material Dialog)
|
|
43
|
+
*/
|
|
44
|
+
abstract confirm(options: ConfirmDialogOptions): Observable<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Get the current page ID from the navigation context
|
|
47
|
+
* Returns null if not on a page edit route
|
|
48
|
+
*/
|
|
49
|
+
abstract getCurrentPageId(): Observable<string | null>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface EditorElement {
|
|
53
|
+
id: string;
|
|
54
|
+
type: string;
|
|
55
|
+
props: Record<string, unknown>;
|
|
56
|
+
slotName?: string;
|
|
57
|
+
children?: EditorElement[];
|
|
58
|
+
adminLabel?: string;
|
|
59
|
+
}
|
|
60
|
+
interface EditorSection {
|
|
61
|
+
id: string;
|
|
62
|
+
type: string;
|
|
63
|
+
props: Record<string, unknown>;
|
|
64
|
+
elements: EditorElement[];
|
|
65
|
+
adminLabel?: string;
|
|
66
|
+
}
|
|
67
|
+
interface HistoryEntry {
|
|
68
|
+
sections: EditorSection[];
|
|
69
|
+
timestamp: number;
|
|
70
|
+
actionType: string;
|
|
71
|
+
}
|
|
72
|
+
interface VisualEditorState {
|
|
73
|
+
sections: EditorSection[];
|
|
74
|
+
selectedElementId: string | null;
|
|
75
|
+
selectedSectionId: string | null;
|
|
76
|
+
isDragging: boolean;
|
|
77
|
+
draggedElementId: string | null;
|
|
78
|
+
history: HistoryEntry[];
|
|
79
|
+
historyIndex: number;
|
|
80
|
+
maxHistorySize: number;
|
|
81
|
+
currentPage: PageContext | null;
|
|
82
|
+
isDirty: boolean;
|
|
83
|
+
}
|
|
84
|
+
declare const initialVisualEditorState: VisualEditorState;
|
|
85
|
+
declare const VISUAL_EDITOR_FEATURE_KEY = "visualEditor";
|
|
86
|
+
|
|
87
|
+
declare const SHOPIFY_API_VERSION = "2026-01";
|
|
88
|
+
interface ShopifyConfig {
|
|
89
|
+
shopDomain: string;
|
|
90
|
+
accessToken: string;
|
|
91
|
+
apiVersion: string;
|
|
92
|
+
}
|
|
93
|
+
declare const SHOPIFY_CONFIG: InjectionToken<ShopifyConfig | Observable<ShopifyConfig>>;
|
|
94
|
+
/**
|
|
95
|
+
* Metafield representation from Shopify
|
|
96
|
+
*/
|
|
97
|
+
interface Metafield {
|
|
98
|
+
id: string;
|
|
99
|
+
namespace: string;
|
|
100
|
+
key: string;
|
|
101
|
+
value: string;
|
|
102
|
+
type: string;
|
|
103
|
+
createdAt?: string;
|
|
104
|
+
updatedAt?: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Page status - draft pages are only visible in admin, published pages are public
|
|
108
|
+
*/
|
|
109
|
+
type PageStatus = 'draft' | 'published';
|
|
110
|
+
/**
|
|
111
|
+
* Entry in the pages index (lightweight reference)
|
|
112
|
+
*/
|
|
113
|
+
interface PageIndexEntry {
|
|
114
|
+
id: string;
|
|
115
|
+
slug: string;
|
|
116
|
+
title: string;
|
|
117
|
+
status: PageStatus;
|
|
118
|
+
updatedAt: string;
|
|
119
|
+
publishedAt?: string;
|
|
120
|
+
size: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Index of all pages stored in a single metafield
|
|
124
|
+
*/
|
|
125
|
+
interface PagesIndex {
|
|
126
|
+
version: number;
|
|
127
|
+
lastUpdated: string;
|
|
128
|
+
pages: PageIndexEntry[];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Full page model with all content
|
|
132
|
+
*/
|
|
133
|
+
interface Page {
|
|
134
|
+
id: string;
|
|
135
|
+
slug: string;
|
|
136
|
+
title: string;
|
|
137
|
+
description?: string;
|
|
138
|
+
sections: EditorSection[];
|
|
139
|
+
status: PageStatus;
|
|
140
|
+
createdAt: string;
|
|
141
|
+
updatedAt: string;
|
|
142
|
+
publishedAt?: string;
|
|
143
|
+
version: number;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Lightweight page summary for listing
|
|
147
|
+
*/
|
|
148
|
+
interface PageSummary {
|
|
149
|
+
id: string;
|
|
150
|
+
slug: string;
|
|
151
|
+
title: string;
|
|
152
|
+
status: PageStatus;
|
|
153
|
+
updatedAt: string;
|
|
154
|
+
publishedAt?: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Page context stored in editor state (minimal info needed while editing)
|
|
158
|
+
*/
|
|
159
|
+
interface PageContext {
|
|
160
|
+
id: string;
|
|
161
|
+
slug: string;
|
|
162
|
+
title: string;
|
|
163
|
+
status: PageStatus;
|
|
164
|
+
version: number;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Request payload for creating a new page
|
|
168
|
+
*/
|
|
169
|
+
interface CreatePageRequest {
|
|
170
|
+
title: string;
|
|
171
|
+
slug: string;
|
|
172
|
+
description?: string;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Request payload for updating an existing page
|
|
176
|
+
*/
|
|
177
|
+
interface UpdatePageRequest {
|
|
178
|
+
title?: string;
|
|
179
|
+
slug?: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
sections?: EditorSection[];
|
|
182
|
+
version: number;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Request payload for publishing/unpublishing
|
|
186
|
+
*/
|
|
187
|
+
interface PublishPageRequest {
|
|
188
|
+
version: number;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Abstract strategy for loading pages into the editor
|
|
193
|
+
* Consumers can implement custom strategies for different use cases
|
|
194
|
+
*/
|
|
195
|
+
declare abstract class PageLoadingStrategy {
|
|
196
|
+
/**
|
|
197
|
+
* Load a page by ID
|
|
198
|
+
*/
|
|
199
|
+
abstract loadPage(pageId: string): Observable<Page>;
|
|
200
|
+
/**
|
|
201
|
+
* Get the current page ID to load
|
|
202
|
+
* This abstracts the source of the page ID (route, input, etc.)
|
|
203
|
+
*/
|
|
204
|
+
abstract getPageIdToLoad(): Observable<string | null>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Default strategy that uses route params via the navigation service
|
|
208
|
+
*/
|
|
209
|
+
declare class RoutePageLoadingStrategy extends PageLoadingStrategy {
|
|
210
|
+
private readonly pageService;
|
|
211
|
+
private readonly navigation;
|
|
212
|
+
loadPage(pageId: string): Observable<Page>;
|
|
213
|
+
getPageIdToLoad(): Observable<string | null>;
|
|
214
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RoutePageLoadingStrategy, never>;
|
|
215
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RoutePageLoadingStrategy>;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Input-based strategy for when page is passed via component input
|
|
219
|
+
* Useful for embedding the editor in modals or custom layouts
|
|
220
|
+
*/
|
|
221
|
+
declare class InputPageLoadingStrategy extends PageLoadingStrategy {
|
|
222
|
+
private readonly pageService;
|
|
223
|
+
private readonly pageId$;
|
|
224
|
+
/**
|
|
225
|
+
* Set the page ID to load
|
|
226
|
+
* Call this when the input changes
|
|
227
|
+
*/
|
|
228
|
+
setPageId(pageId: string | null): void;
|
|
229
|
+
loadPage(pageId: string): Observable<Page>;
|
|
230
|
+
getPageIdToLoad(): Observable<string | null>;
|
|
231
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<InputPageLoadingStrategy, never>;
|
|
232
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<InputPageLoadingStrategy>;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Configuration for the default router navigation
|
|
237
|
+
*/
|
|
238
|
+
interface RouterNavigationConfig {
|
|
239
|
+
/** Route path for page list (default: '/admin') */
|
|
240
|
+
pageListPath: string;
|
|
241
|
+
/** Route path pattern for page edit (default: '/admin/pages/:pageId') */
|
|
242
|
+
pageEditPath: string;
|
|
243
|
+
/** Route path pattern for preview (optional) */
|
|
244
|
+
pagePreviewPath?: string;
|
|
245
|
+
/** Route param name for page ID (default: 'pageId') */
|
|
246
|
+
pageIdParam: string;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Default router navigation configuration
|
|
250
|
+
*/
|
|
251
|
+
declare const DEFAULT_ROUTER_NAVIGATION_CONFIG: RouterNavigationConfig;
|
|
252
|
+
/**
|
|
253
|
+
* Injection token for router navigation configuration
|
|
254
|
+
*/
|
|
255
|
+
declare const ROUTER_NAVIGATION_CONFIG: InjectionToken<RouterNavigationConfig>;
|
|
256
|
+
/**
|
|
257
|
+
* Default navigation service implementation using Angular Router
|
|
258
|
+
*/
|
|
259
|
+
declare class DefaultRouterNavigationService extends VisualEditorNavigation {
|
|
260
|
+
private readonly router;
|
|
261
|
+
private readonly route;
|
|
262
|
+
private readonly config;
|
|
263
|
+
navigate(target: VisualEditorNavigationTarget): void;
|
|
264
|
+
confirm(options: ConfirmDialogOptions): Observable<boolean>;
|
|
265
|
+
getCurrentPageId(): Observable<string | null>;
|
|
266
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DefaultRouterNavigationService, never>;
|
|
267
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DefaultRouterNavigationService>;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Main configuration interface for the Visual Editor library
|
|
272
|
+
*/
|
|
273
|
+
interface VisualEditorConfig {
|
|
274
|
+
/**
|
|
275
|
+
* Navigation configuration
|
|
276
|
+
*/
|
|
277
|
+
navigation?: {
|
|
278
|
+
/**
|
|
279
|
+
* Custom navigation service class
|
|
280
|
+
* If provided, routerConfig is ignored
|
|
281
|
+
*/
|
|
282
|
+
navigationService?: Type<VisualEditorNavigation>;
|
|
283
|
+
/**
|
|
284
|
+
* Router-based config (used with DefaultRouterNavigationService)
|
|
285
|
+
* Only used if navigationService is not provided
|
|
286
|
+
*/
|
|
287
|
+
routerConfig?: Partial<RouterNavigationConfig>;
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Page loading configuration
|
|
291
|
+
*/
|
|
292
|
+
pageLoading?: {
|
|
293
|
+
/**
|
|
294
|
+
* Custom page loading strategy
|
|
295
|
+
* Defaults to RoutePageLoadingStrategy
|
|
296
|
+
*/
|
|
297
|
+
strategy?: Type<PageLoadingStrategy>;
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Page service configuration
|
|
301
|
+
*/
|
|
302
|
+
pages?: {
|
|
303
|
+
/**
|
|
304
|
+
* Use in-memory storage instead of Shopify
|
|
305
|
+
* Useful for development and demos
|
|
306
|
+
* Defaults to false (uses Shopify)
|
|
307
|
+
*/
|
|
308
|
+
useInMemory?: boolean;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* UI configuration
|
|
312
|
+
*/
|
|
313
|
+
ui?: {
|
|
314
|
+
/**
|
|
315
|
+
* Show back button in editor toolbar
|
|
316
|
+
* Defaults to true
|
|
317
|
+
*/
|
|
318
|
+
showBackButton?: boolean;
|
|
319
|
+
/**
|
|
320
|
+
* Show publish/unpublish buttons
|
|
321
|
+
* Defaults to true
|
|
322
|
+
*/
|
|
323
|
+
showPublishButtons?: boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Show save button
|
|
326
|
+
* Defaults to true
|
|
327
|
+
*/
|
|
328
|
+
showSaveButton?: boolean;
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Injection token for the Visual Editor configuration
|
|
333
|
+
*/
|
|
334
|
+
declare const VISUAL_EDITOR_CONFIG: InjectionToken<VisualEditorConfig>;
|
|
335
|
+
/**
|
|
336
|
+
* Default configuration values
|
|
337
|
+
*/
|
|
338
|
+
declare const DEFAULT_VISUAL_EDITOR_CONFIG: Required<VisualEditorConfig>;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Provides all necessary services and configuration for the Visual Editor
|
|
342
|
+
*
|
|
343
|
+
* Note: You must also call provideVisualEditorStore() to set up the NgRx state.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```typescript
|
|
347
|
+
* // Minimal setup (uses Shopify by default)
|
|
348
|
+
* export const appConfig: ApplicationConfig = {
|
|
349
|
+
* providers: [
|
|
350
|
+
* provideStore(),
|
|
351
|
+
* provideVisualEditorStore(), // Required: sets up NgRx state
|
|
352
|
+
* provideVisualEditor(), // Sets up services and config
|
|
353
|
+
* provideEditorComponents(myComponents),
|
|
354
|
+
* ],
|
|
355
|
+
* };
|
|
356
|
+
*
|
|
357
|
+
* // With custom configuration
|
|
358
|
+
* provideVisualEditor({
|
|
359
|
+
* navigation: {
|
|
360
|
+
* routerConfig: {
|
|
361
|
+
* pageListPath: '/cms',
|
|
362
|
+
* pageEditPath: '/cms/editor/:id',
|
|
363
|
+
* pageIdParam: 'id',
|
|
364
|
+
* }
|
|
365
|
+
* },
|
|
366
|
+
* pages: {
|
|
367
|
+
* useInMemory: true // Use in-memory storage for development
|
|
368
|
+
* }
|
|
369
|
+
* })
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
372
|
+
declare function provideVisualEditor(config?: VisualEditorConfig): EnvironmentProviders;
|
|
373
|
+
|
|
374
|
+
declare const VisualEditorActions: {
|
|
375
|
+
addSection: _ngrx_store.ActionCreator<"[Visual Editor] Add Section", (props: {
|
|
376
|
+
section: EditorSection;
|
|
377
|
+
index?: number;
|
|
378
|
+
}) => {
|
|
379
|
+
section: EditorSection;
|
|
380
|
+
index?: number;
|
|
381
|
+
} & _ngrx_store.Action<"[Visual Editor] Add Section">>;
|
|
382
|
+
removeSection: _ngrx_store.ActionCreator<"[Visual Editor] Remove Section", (props: {
|
|
383
|
+
sectionId: string;
|
|
384
|
+
}) => {
|
|
385
|
+
sectionId: string;
|
|
386
|
+
} & _ngrx_store.Action<"[Visual Editor] Remove Section">>;
|
|
387
|
+
moveSection: _ngrx_store.ActionCreator<"[Visual Editor] Move Section", (props: {
|
|
388
|
+
sectionId: string;
|
|
389
|
+
newIndex: number;
|
|
390
|
+
}) => {
|
|
391
|
+
sectionId: string;
|
|
392
|
+
newIndex: number;
|
|
393
|
+
} & _ngrx_store.Action<"[Visual Editor] Move Section">>;
|
|
394
|
+
updateSection: _ngrx_store.ActionCreator<"[Visual Editor] Update Section", (props: {
|
|
395
|
+
sectionId: string;
|
|
396
|
+
changes: Partial<EditorSection>;
|
|
397
|
+
}) => {
|
|
398
|
+
sectionId: string;
|
|
399
|
+
changes: Partial<EditorSection>;
|
|
400
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Section">>;
|
|
401
|
+
updateSectionProps: _ngrx_store.ActionCreator<"[Visual Editor] Update Section Props", (props: {
|
|
402
|
+
sectionId: string;
|
|
403
|
+
props: Record<string, unknown>;
|
|
404
|
+
}) => {
|
|
405
|
+
sectionId: string;
|
|
406
|
+
props: Record<string, unknown>;
|
|
407
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Section Props">>;
|
|
408
|
+
addElement: _ngrx_store.ActionCreator<"[Visual Editor] Add Element", (props: {
|
|
409
|
+
sectionId: string;
|
|
410
|
+
element: EditorElement;
|
|
411
|
+
index?: number;
|
|
412
|
+
}) => {
|
|
413
|
+
sectionId: string;
|
|
414
|
+
element: EditorElement;
|
|
415
|
+
index?: number;
|
|
416
|
+
} & _ngrx_store.Action<"[Visual Editor] Add Element">>;
|
|
417
|
+
removeElement: _ngrx_store.ActionCreator<"[Visual Editor] Remove Element", (props: {
|
|
418
|
+
sectionId: string;
|
|
419
|
+
elementId: string;
|
|
420
|
+
}) => {
|
|
421
|
+
sectionId: string;
|
|
422
|
+
elementId: string;
|
|
423
|
+
} & _ngrx_store.Action<"[Visual Editor] Remove Element">>;
|
|
424
|
+
moveElement: _ngrx_store.ActionCreator<"[Visual Editor] Move Element", (props: {
|
|
425
|
+
sourceSectionId: string;
|
|
426
|
+
targetSectionId: string;
|
|
427
|
+
elementId: string;
|
|
428
|
+
newIndex: number;
|
|
429
|
+
}) => {
|
|
430
|
+
sourceSectionId: string;
|
|
431
|
+
targetSectionId: string;
|
|
432
|
+
elementId: string;
|
|
433
|
+
newIndex: number;
|
|
434
|
+
} & _ngrx_store.Action<"[Visual Editor] Move Element">>;
|
|
435
|
+
updateElement: _ngrx_store.ActionCreator<"[Visual Editor] Update Element", (props: {
|
|
436
|
+
sectionId: string;
|
|
437
|
+
elementId: string;
|
|
438
|
+
changes: Partial<EditorElement>;
|
|
439
|
+
}) => {
|
|
440
|
+
sectionId: string;
|
|
441
|
+
elementId: string;
|
|
442
|
+
changes: Partial<EditorElement>;
|
|
443
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Element">>;
|
|
444
|
+
updateElementProps: _ngrx_store.ActionCreator<"[Visual Editor] Update Element Props", (props: {
|
|
445
|
+
sectionId: string;
|
|
446
|
+
elementId: string;
|
|
447
|
+
props: Record<string, unknown>;
|
|
448
|
+
}) => {
|
|
449
|
+
sectionId: string;
|
|
450
|
+
elementId: string;
|
|
451
|
+
props: Record<string, unknown>;
|
|
452
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Element Props">>;
|
|
453
|
+
addBlock: _ngrx_store.ActionCreator<"[Visual Editor] Add Block", (props: {
|
|
454
|
+
sectionId: string;
|
|
455
|
+
slotName: string;
|
|
456
|
+
element: EditorElement;
|
|
457
|
+
index?: number;
|
|
458
|
+
}) => {
|
|
459
|
+
sectionId: string;
|
|
460
|
+
slotName: string;
|
|
461
|
+
element: EditorElement;
|
|
462
|
+
index?: number;
|
|
463
|
+
} & _ngrx_store.Action<"[Visual Editor] Add Block">>;
|
|
464
|
+
removeBlock: _ngrx_store.ActionCreator<"[Visual Editor] Remove Block", (props: {
|
|
465
|
+
sectionId: string;
|
|
466
|
+
elementId: string;
|
|
467
|
+
}) => {
|
|
468
|
+
sectionId: string;
|
|
469
|
+
elementId: string;
|
|
470
|
+
} & _ngrx_store.Action<"[Visual Editor] Remove Block">>;
|
|
471
|
+
moveBlock: _ngrx_store.ActionCreator<"[Visual Editor] Move Block", (props: {
|
|
472
|
+
sectionId: string;
|
|
473
|
+
elementId: string;
|
|
474
|
+
targetSlotName: string;
|
|
475
|
+
newIndex: number;
|
|
476
|
+
}) => {
|
|
477
|
+
sectionId: string;
|
|
478
|
+
elementId: string;
|
|
479
|
+
targetSlotName: string;
|
|
480
|
+
newIndex: number;
|
|
481
|
+
} & _ngrx_store.Action<"[Visual Editor] Move Block">>;
|
|
482
|
+
updateBlockProps: _ngrx_store.ActionCreator<"[Visual Editor] Update Block Props", (props: {
|
|
483
|
+
sectionId: string;
|
|
484
|
+
elementId: string;
|
|
485
|
+
props: Record<string, unknown>;
|
|
486
|
+
}) => {
|
|
487
|
+
sectionId: string;
|
|
488
|
+
elementId: string;
|
|
489
|
+
props: Record<string, unknown>;
|
|
490
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Block Props">>;
|
|
491
|
+
renameSection: _ngrx_store.ActionCreator<"[Visual Editor] Rename Section", (props: {
|
|
492
|
+
sectionId: string;
|
|
493
|
+
adminLabel: string;
|
|
494
|
+
}) => {
|
|
495
|
+
sectionId: string;
|
|
496
|
+
adminLabel: string;
|
|
497
|
+
} & _ngrx_store.Action<"[Visual Editor] Rename Section">>;
|
|
498
|
+
renameBlock: _ngrx_store.ActionCreator<"[Visual Editor] Rename Block", (props: {
|
|
499
|
+
sectionId: string;
|
|
500
|
+
elementId: string;
|
|
501
|
+
adminLabel: string;
|
|
502
|
+
}) => {
|
|
503
|
+
sectionId: string;
|
|
504
|
+
elementId: string;
|
|
505
|
+
adminLabel: string;
|
|
506
|
+
} & _ngrx_store.Action<"[Visual Editor] Rename Block">>;
|
|
507
|
+
duplicateSection: _ngrx_store.ActionCreator<"[Visual Editor] Duplicate Section", (props: {
|
|
508
|
+
sectionId: string;
|
|
509
|
+
}) => {
|
|
510
|
+
sectionId: string;
|
|
511
|
+
} & _ngrx_store.Action<"[Visual Editor] Duplicate Section">>;
|
|
512
|
+
duplicateBlock: _ngrx_store.ActionCreator<"[Visual Editor] Duplicate Block", (props: {
|
|
513
|
+
sectionId: string;
|
|
514
|
+
elementId: string;
|
|
515
|
+
}) => {
|
|
516
|
+
sectionId: string;
|
|
517
|
+
elementId: string;
|
|
518
|
+
} & _ngrx_store.Action<"[Visual Editor] Duplicate Block">>;
|
|
519
|
+
duplicateNestedBlock: _ngrx_store.ActionCreator<"[Visual Editor] Duplicate Nested Block", (props: {
|
|
520
|
+
sectionId: string;
|
|
521
|
+
parentPath: string[];
|
|
522
|
+
elementId: string;
|
|
523
|
+
}) => {
|
|
524
|
+
sectionId: string;
|
|
525
|
+
parentPath: string[];
|
|
526
|
+
elementId: string;
|
|
527
|
+
} & _ngrx_store.Action<"[Visual Editor] Duplicate Nested Block">>;
|
|
528
|
+
addNestedBlock: _ngrx_store.ActionCreator<"[Visual Editor] Add Nested Block", (props: {
|
|
529
|
+
sectionId: string;
|
|
530
|
+
parentPath: string[];
|
|
531
|
+
slotName: string;
|
|
532
|
+
element: EditorElement;
|
|
533
|
+
index?: number;
|
|
534
|
+
}) => {
|
|
535
|
+
sectionId: string;
|
|
536
|
+
parentPath: string[];
|
|
537
|
+
slotName: string;
|
|
538
|
+
element: EditorElement;
|
|
539
|
+
index?: number;
|
|
540
|
+
} & _ngrx_store.Action<"[Visual Editor] Add Nested Block">>;
|
|
541
|
+
removeNestedBlock: _ngrx_store.ActionCreator<"[Visual Editor] Remove Nested Block", (props: {
|
|
542
|
+
sectionId: string;
|
|
543
|
+
parentPath: string[];
|
|
544
|
+
elementId: string;
|
|
545
|
+
}) => {
|
|
546
|
+
sectionId: string;
|
|
547
|
+
parentPath: string[];
|
|
548
|
+
elementId: string;
|
|
549
|
+
} & _ngrx_store.Action<"[Visual Editor] Remove Nested Block">>;
|
|
550
|
+
updateNestedBlockProps: _ngrx_store.ActionCreator<"[Visual Editor] Update Nested Block Props", (props: {
|
|
551
|
+
sectionId: string;
|
|
552
|
+
parentPath: string[];
|
|
553
|
+
elementId: string;
|
|
554
|
+
props: Record<string, unknown>;
|
|
555
|
+
}) => {
|
|
556
|
+
sectionId: string;
|
|
557
|
+
parentPath: string[];
|
|
558
|
+
elementId: string;
|
|
559
|
+
props: Record<string, unknown>;
|
|
560
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Nested Block Props">>;
|
|
561
|
+
moveNestedBlock: _ngrx_store.ActionCreator<"[Visual Editor] Move Nested Block", (props: {
|
|
562
|
+
sectionId: string;
|
|
563
|
+
parentPath: string[];
|
|
564
|
+
elementId: string;
|
|
565
|
+
targetSlotName: string;
|
|
566
|
+
newIndex: number;
|
|
567
|
+
}) => {
|
|
568
|
+
sectionId: string;
|
|
569
|
+
parentPath: string[];
|
|
570
|
+
elementId: string;
|
|
571
|
+
targetSlotName: string;
|
|
572
|
+
newIndex: number;
|
|
573
|
+
} & _ngrx_store.Action<"[Visual Editor] Move Nested Block">>;
|
|
574
|
+
reparentBlock: _ngrx_store.ActionCreator<"[Visual Editor] Reparent Block", (props: {
|
|
575
|
+
sourceSectionId: string;
|
|
576
|
+
sourceParentPath: string[];
|
|
577
|
+
elementId: string;
|
|
578
|
+
targetSectionId: string;
|
|
579
|
+
targetParentPath: string[];
|
|
580
|
+
targetSlotName: string;
|
|
581
|
+
targetIndex: number;
|
|
582
|
+
}) => {
|
|
583
|
+
sourceSectionId: string;
|
|
584
|
+
sourceParentPath: string[];
|
|
585
|
+
elementId: string;
|
|
586
|
+
targetSectionId: string;
|
|
587
|
+
targetParentPath: string[];
|
|
588
|
+
targetSlotName: string;
|
|
589
|
+
targetIndex: number;
|
|
590
|
+
} & _ngrx_store.Action<"[Visual Editor] Reparent Block">>;
|
|
591
|
+
selectElement: _ngrx_store.ActionCreator<"[Visual Editor] Select Element", (props: {
|
|
592
|
+
sectionId: string | null;
|
|
593
|
+
elementId: string | null;
|
|
594
|
+
}) => {
|
|
595
|
+
sectionId: string | null;
|
|
596
|
+
elementId: string | null;
|
|
597
|
+
} & _ngrx_store.Action<"[Visual Editor] Select Element">>;
|
|
598
|
+
clearSelection: _ngrx_store.ActionCreator<"[Visual Editor] Clear Selection", () => _ngrx_store.Action<"[Visual Editor] Clear Selection">>;
|
|
599
|
+
startDrag: _ngrx_store.ActionCreator<"[Visual Editor] Start Drag", (props: {
|
|
600
|
+
elementId: string;
|
|
601
|
+
}) => {
|
|
602
|
+
elementId: string;
|
|
603
|
+
} & _ngrx_store.Action<"[Visual Editor] Start Drag">>;
|
|
604
|
+
endDrag: _ngrx_store.ActionCreator<"[Visual Editor] End Drag", () => _ngrx_store.Action<"[Visual Editor] End Drag">>;
|
|
605
|
+
undo: _ngrx_store.ActionCreator<"[Visual Editor] Undo", () => _ngrx_store.Action<"[Visual Editor] Undo">>;
|
|
606
|
+
redo: _ngrx_store.ActionCreator<"[Visual Editor] Redo", () => _ngrx_store.Action<"[Visual Editor] Redo">>;
|
|
607
|
+
clearHistory: _ngrx_store.ActionCreator<"[Visual Editor] Clear History", () => _ngrx_store.Action<"[Visual Editor] Clear History">>;
|
|
608
|
+
loadSections: _ngrx_store.ActionCreator<"[Visual Editor] Load Sections", (props: {
|
|
609
|
+
sections: EditorSection[];
|
|
610
|
+
}) => {
|
|
611
|
+
sections: EditorSection[];
|
|
612
|
+
} & _ngrx_store.Action<"[Visual Editor] Load Sections">>;
|
|
613
|
+
resetEditor: _ngrx_store.ActionCreator<"[Visual Editor] Reset Editor", () => _ngrx_store.Action<"[Visual Editor] Reset Editor">>;
|
|
614
|
+
loadPage: _ngrx_store.ActionCreator<"[Visual Editor] Load Page", (props: {
|
|
615
|
+
page: Page;
|
|
616
|
+
}) => {
|
|
617
|
+
page: Page;
|
|
618
|
+
} & _ngrx_store.Action<"[Visual Editor] Load Page">>;
|
|
619
|
+
updatePageContext: _ngrx_store.ActionCreator<"[Visual Editor] Update Page Context", (props: {
|
|
620
|
+
context: Partial<PageContext>;
|
|
621
|
+
}) => {
|
|
622
|
+
context: Partial<PageContext>;
|
|
623
|
+
} & _ngrx_store.Action<"[Visual Editor] Update Page Context">>;
|
|
624
|
+
markDirty: _ngrx_store.ActionCreator<"[Visual Editor] Mark Dirty", () => _ngrx_store.Action<"[Visual Editor] Mark Dirty">>;
|
|
625
|
+
markClean: _ngrx_store.ActionCreator<"[Visual Editor] Mark Clean", () => _ngrx_store.Action<"[Visual Editor] Mark Clean">>;
|
|
626
|
+
clearPage: _ngrx_store.ActionCreator<"[Visual Editor] Clear Page", () => _ngrx_store.Action<"[Visual Editor] Clear Page">>;
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
declare const visualEditorReducer: _ngrx_store.ActionReducer<VisualEditorState, _ngrx_store.Action<string>>;
|
|
630
|
+
|
|
631
|
+
declare const selectVisualEditorState: _ngrx_store.MemoizedSelector<object, VisualEditorState, _ngrx_store.DefaultProjectorFn<VisualEditorState>>;
|
|
632
|
+
declare const selectSections: _ngrx_store.MemoizedSelector<object, _kustomizer_visual_editor.EditorSection[], (s1: VisualEditorState) => _kustomizer_visual_editor.EditorSection[]>;
|
|
633
|
+
declare const selectSelectedElementId: _ngrx_store.MemoizedSelector<object, string | null, (s1: VisualEditorState) => string | null>;
|
|
634
|
+
declare const selectSelectedSectionId: _ngrx_store.MemoizedSelector<object, string | null, (s1: VisualEditorState) => string | null>;
|
|
635
|
+
declare const selectIsDragging: _ngrx_store.MemoizedSelector<object, boolean, (s1: VisualEditorState) => boolean>;
|
|
636
|
+
declare const selectDraggedElementId: _ngrx_store.MemoizedSelector<object, string | null, (s1: VisualEditorState) => string | null>;
|
|
637
|
+
declare const selectHistoryIndex: _ngrx_store.MemoizedSelector<object, number, (s1: VisualEditorState) => number>;
|
|
638
|
+
declare const selectHistoryLength: _ngrx_store.MemoizedSelector<object, number, (s1: VisualEditorState) => number>;
|
|
639
|
+
declare const selectCanUndo: _ngrx_store.MemoizedSelector<object, boolean, (s1: VisualEditorState) => boolean>;
|
|
640
|
+
declare const selectCanRedo: _ngrx_store.MemoizedSelector<object, boolean, (s1: VisualEditorState) => boolean>;
|
|
641
|
+
declare const selectSelectedSection: _ngrx_store.MemoizedSelector<object, _kustomizer_visual_editor.EditorSection | null, (s1: _kustomizer_visual_editor.EditorSection[], s2: string | null) => _kustomizer_visual_editor.EditorSection | null>;
|
|
642
|
+
declare const selectSelectedElement: _ngrx_store.MemoizedSelector<object, EditorElement | null, (s1: _kustomizer_visual_editor.EditorSection | null, s2: string | null) => EditorElement | null>;
|
|
643
|
+
declare const selectSectionById: (sectionId: string) => _ngrx_store.MemoizedSelector<object, _kustomizer_visual_editor.EditorSection | null, (s1: _kustomizer_visual_editor.EditorSection[]) => _kustomizer_visual_editor.EditorSection | null>;
|
|
644
|
+
declare const selectElementById: (sectionId: string, elementId: string) => _ngrx_store.MemoizedSelector<object, EditorElement | null, (s1: _kustomizer_visual_editor.EditorSection | null) => EditorElement | null>;
|
|
645
|
+
declare const selectHistory: _ngrx_store.MemoizedSelector<object, _kustomizer_visual_editor.HistoryEntry[], (s1: VisualEditorState) => _kustomizer_visual_editor.HistoryEntry[]>;
|
|
646
|
+
declare const selectLastAction: _ngrx_store.MemoizedSelector<object, string | null, (s1: _kustomizer_visual_editor.HistoryEntry[], s2: number) => string | null>;
|
|
647
|
+
declare const selectSelectedElementType: _ngrx_store.MemoizedSelector<object, string | null, (s1: EditorElement | null) => string | null>;
|
|
648
|
+
declare const selectSelectedSectionType: _ngrx_store.MemoizedSelector<object, string | null, (s1: _kustomizer_visual_editor.EditorSection | null) => string | null>;
|
|
649
|
+
declare const selectBlocksForSection: (sectionId: string) => _ngrx_store.MemoizedSelector<object, EditorElement[], (s1: _kustomizer_visual_editor.EditorSection | null) => EditorElement[]>;
|
|
650
|
+
declare const selectBlocksForSlot: (sectionId: string, slotName: string) => _ngrx_store.MemoizedSelector<object, EditorElement[], (s1: EditorElement[]) => EditorElement[]>;
|
|
651
|
+
declare const selectSelectedBlock: _ngrx_store.MemoizedSelector<object, EditorElement | null, (s1: _kustomizer_visual_editor.EditorSection | null, s2: string | null) => EditorElement | null>;
|
|
652
|
+
declare const selectSelectedBlockSlotName: _ngrx_store.MemoizedSelector<object, string | null, (s1: EditorElement | null) => string | null>;
|
|
653
|
+
declare const selectCurrentPage: _ngrx_store.MemoizedSelector<object, _kustomizer_visual_editor.PageContext | null, (s1: VisualEditorState) => _kustomizer_visual_editor.PageContext | null>;
|
|
654
|
+
declare const selectCurrentPageId: _ngrx_store.MemoizedSelector<object, string | null, (s1: _kustomizer_visual_editor.PageContext | null) => string | null>;
|
|
655
|
+
declare const selectCurrentPageSlug: _ngrx_store.MemoizedSelector<object, string | null, (s1: _kustomizer_visual_editor.PageContext | null) => string | null>;
|
|
656
|
+
declare const selectCurrentPageTitle: _ngrx_store.MemoizedSelector<object, string | null, (s1: _kustomizer_visual_editor.PageContext | null) => string | null>;
|
|
657
|
+
declare const selectCurrentPageStatus: _ngrx_store.MemoizedSelector<object, _kustomizer_visual_editor.PageStatus | null, (s1: _kustomizer_visual_editor.PageContext | null) => _kustomizer_visual_editor.PageStatus | null>;
|
|
658
|
+
declare const selectCurrentPageVersion: _ngrx_store.MemoizedSelector<object, number | null, (s1: _kustomizer_visual_editor.PageContext | null) => number | null>;
|
|
659
|
+
declare const selectIsDirty: _ngrx_store.MemoizedSelector<object, boolean, (s1: VisualEditorState) => boolean>;
|
|
660
|
+
declare const selectIsPageLoaded: _ngrx_store.MemoizedSelector<object, boolean, (s1: _kustomizer_visual_editor.PageContext | null) => boolean>;
|
|
661
|
+
|
|
662
|
+
declare function provideVisualEditorStore(): EnvironmentProviders;
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Supported property types for the editor
|
|
666
|
+
*/
|
|
667
|
+
type PropType = 'string' | 'number' | 'boolean' | 'color' | 'image' | 'video' | 'url' | 'richtext' | 'textarea' | 'select' | 'range' | 'json';
|
|
668
|
+
/**
|
|
669
|
+
* Option for select-type properties
|
|
670
|
+
*/
|
|
671
|
+
interface SelectOption {
|
|
672
|
+
label: string;
|
|
673
|
+
value: string | number;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Validation rules for a property
|
|
677
|
+
*/
|
|
678
|
+
interface PropValidation {
|
|
679
|
+
required?: boolean;
|
|
680
|
+
min?: number;
|
|
681
|
+
max?: number;
|
|
682
|
+
minLength?: number;
|
|
683
|
+
maxLength?: number;
|
|
684
|
+
pattern?: string;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Condition to show/hide a property based on another property's value
|
|
688
|
+
*/
|
|
689
|
+
interface PropCondition {
|
|
690
|
+
dependsOn: string;
|
|
691
|
+
equals?: unknown;
|
|
692
|
+
oneOf?: unknown[];
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Schema definition for a single property
|
|
696
|
+
*/
|
|
697
|
+
interface PropSchema<T = unknown> {
|
|
698
|
+
type: PropType;
|
|
699
|
+
label: string;
|
|
700
|
+
description?: string;
|
|
701
|
+
defaultValue: T;
|
|
702
|
+
placeholder?: string;
|
|
703
|
+
validation?: PropValidation;
|
|
704
|
+
condition?: PropCondition;
|
|
705
|
+
group?: string;
|
|
706
|
+
order?: number;
|
|
707
|
+
options?: SelectOption[];
|
|
708
|
+
step?: number;
|
|
709
|
+
accept?: string[];
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Map of property names to their schemas
|
|
713
|
+
*/
|
|
714
|
+
type PropSchemaMap = Record<string, PropSchema>;
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Constraints for what can be placed in a slot
|
|
718
|
+
*/
|
|
719
|
+
interface SlotConstraints {
|
|
720
|
+
allowedTypes?: string[];
|
|
721
|
+
disallowedTypes?: string[];
|
|
722
|
+
minItems?: number;
|
|
723
|
+
maxItems?: number;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Definition of a slot where child components can be inserted
|
|
727
|
+
*/
|
|
728
|
+
interface SlotDefinition {
|
|
729
|
+
name: string;
|
|
730
|
+
label: string;
|
|
731
|
+
description?: string;
|
|
732
|
+
constraints?: SlotConstraints;
|
|
733
|
+
emptyPlaceholder?: string;
|
|
734
|
+
droppable?: boolean;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Category for grouping components in the editor panel
|
|
739
|
+
*/
|
|
740
|
+
type ComponentCategory = 'layout' | 'content' | 'media' | 'form' | 'navigation' | 'commerce' | 'custom';
|
|
741
|
+
/**
|
|
742
|
+
* Block configuration within a preset
|
|
743
|
+
*/
|
|
744
|
+
interface PresetBlockConfig {
|
|
745
|
+
type: string;
|
|
746
|
+
settings?: Record<string, unknown>;
|
|
747
|
+
slotName?: string;
|
|
748
|
+
blocks?: PresetBlockConfig[];
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Pre-configured variant of a component
|
|
752
|
+
*/
|
|
753
|
+
interface ComponentPreset {
|
|
754
|
+
name: string;
|
|
755
|
+
category?: string;
|
|
756
|
+
description?: string;
|
|
757
|
+
icon?: string;
|
|
758
|
+
thumbnail?: string;
|
|
759
|
+
settings?: Record<string, unknown>;
|
|
760
|
+
blocks?: PresetBlockConfig[];
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Complete definition of a registered editor component
|
|
764
|
+
*/
|
|
765
|
+
interface ComponentDefinition<TProps extends Record<string, unknown> = Record<string, unknown>> {
|
|
766
|
+
/**
|
|
767
|
+
* Unique identifier matching EditorElement.type or EditorSection.type
|
|
768
|
+
*/
|
|
769
|
+
type: string;
|
|
770
|
+
/**
|
|
771
|
+
* Display name in the component panel
|
|
772
|
+
*/
|
|
773
|
+
name: string;
|
|
774
|
+
/**
|
|
775
|
+
* Description of the component
|
|
776
|
+
*/
|
|
777
|
+
description?: string;
|
|
778
|
+
/**
|
|
779
|
+
* Category for grouping in the component panel
|
|
780
|
+
*/
|
|
781
|
+
category: ComponentCategory;
|
|
782
|
+
/**
|
|
783
|
+
* Icon name or URL
|
|
784
|
+
*/
|
|
785
|
+
icon?: string;
|
|
786
|
+
/**
|
|
787
|
+
* Angular component class to render
|
|
788
|
+
*/
|
|
789
|
+
component: Type<unknown>;
|
|
790
|
+
/**
|
|
791
|
+
* Schema of editable properties
|
|
792
|
+
*/
|
|
793
|
+
props: PropSchemaMap;
|
|
794
|
+
/**
|
|
795
|
+
* Available slots for child components
|
|
796
|
+
*/
|
|
797
|
+
slots?: SlotDefinition[];
|
|
798
|
+
/**
|
|
799
|
+
* Whether this is a section (top-level container) vs element
|
|
800
|
+
*/
|
|
801
|
+
isSection?: boolean;
|
|
802
|
+
/**
|
|
803
|
+
* Whether this is a block (element that lives inside section slots)
|
|
804
|
+
*/
|
|
805
|
+
isBlock?: boolean;
|
|
806
|
+
/**
|
|
807
|
+
* Scope of the block: 'theme' = available in all sections, 'section' = only in specific sections
|
|
808
|
+
* Defaults to 'theme' if not specified
|
|
809
|
+
*/
|
|
810
|
+
blockScope?: 'section' | 'theme';
|
|
811
|
+
/**
|
|
812
|
+
* Section types where this block is available (only used when blockScope is 'section')
|
|
813
|
+
*/
|
|
814
|
+
sectionTypes?: string[];
|
|
815
|
+
/**
|
|
816
|
+
* Whether the component can be dragged/reordered
|
|
817
|
+
*/
|
|
818
|
+
draggable?: boolean;
|
|
819
|
+
/**
|
|
820
|
+
* Whether the component can be deleted
|
|
821
|
+
*/
|
|
822
|
+
deletable?: boolean;
|
|
823
|
+
/**
|
|
824
|
+
* Whether the component can be duplicated
|
|
825
|
+
*/
|
|
826
|
+
duplicable?: boolean;
|
|
827
|
+
/**
|
|
828
|
+
* Thumbnail URL for the component panel
|
|
829
|
+
*/
|
|
830
|
+
thumbnail?: string;
|
|
831
|
+
/**
|
|
832
|
+
* Tags for search
|
|
833
|
+
*/
|
|
834
|
+
tags?: string[];
|
|
835
|
+
/**
|
|
836
|
+
* Order in the component list (lower = first)
|
|
837
|
+
*/
|
|
838
|
+
order?: number;
|
|
839
|
+
/**
|
|
840
|
+
* Pre-configured presets for this component.
|
|
841
|
+
* Each preset appears as a separate entry in the picker.
|
|
842
|
+
*/
|
|
843
|
+
presets?: ComponentPreset[];
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* A resolved preset entry for use in pickers.
|
|
848
|
+
* If the component has no presets, preset is null and display fields come from the definition.
|
|
849
|
+
*/
|
|
850
|
+
interface ResolvedPreset {
|
|
851
|
+
definition: ComponentDefinition;
|
|
852
|
+
preset: ComponentPreset | null;
|
|
853
|
+
displayName: string;
|
|
854
|
+
displayCategory: string;
|
|
855
|
+
displayIcon: string | undefined;
|
|
856
|
+
displayDescription: string | undefined;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Central service for registering and querying editor components
|
|
860
|
+
*/
|
|
861
|
+
declare class ComponentRegistryService {
|
|
862
|
+
private readonly definitions;
|
|
863
|
+
private readonly injectedDefinitions;
|
|
864
|
+
constructor();
|
|
865
|
+
/**
|
|
866
|
+
* Register a component definition
|
|
867
|
+
*/
|
|
868
|
+
register(definition: ComponentDefinition): void;
|
|
869
|
+
/**
|
|
870
|
+
* Register multiple definitions
|
|
871
|
+
*/
|
|
872
|
+
registerAll(definitions: ComponentDefinition[]): void;
|
|
873
|
+
/**
|
|
874
|
+
* Get a definition by type
|
|
875
|
+
*/
|
|
876
|
+
get(type: string): ComponentDefinition | undefined;
|
|
877
|
+
/**
|
|
878
|
+
* Check if a type is registered
|
|
879
|
+
*/
|
|
880
|
+
has(type: string): boolean;
|
|
881
|
+
/**
|
|
882
|
+
* Get the Angular component for a type
|
|
883
|
+
*/
|
|
884
|
+
getComponent(type: string): Type<unknown> | undefined;
|
|
885
|
+
/**
|
|
886
|
+
* Get the props schema for a type
|
|
887
|
+
*/
|
|
888
|
+
getPropsSchema(type: string): PropSchemaMap | undefined;
|
|
889
|
+
/**
|
|
890
|
+
* Get the slots for a type
|
|
891
|
+
*/
|
|
892
|
+
getSlots(type: string): SlotDefinition[];
|
|
893
|
+
/**
|
|
894
|
+
* Check if a component type has slots (can contain nested blocks)
|
|
895
|
+
*/
|
|
896
|
+
hasSlots(type: string): boolean;
|
|
897
|
+
/**
|
|
898
|
+
* Get all definitions
|
|
899
|
+
*/
|
|
900
|
+
getAll(): ComponentDefinition[];
|
|
901
|
+
/**
|
|
902
|
+
* Get definitions filtered by category
|
|
903
|
+
*/
|
|
904
|
+
getByCategory(category: ComponentCategory): ComponentDefinition[];
|
|
905
|
+
/**
|
|
906
|
+
* Get only section components
|
|
907
|
+
*/
|
|
908
|
+
getSections(): ComponentDefinition[];
|
|
909
|
+
/**
|
|
910
|
+
* Get only element components (non-sections, non-blocks)
|
|
911
|
+
*/
|
|
912
|
+
getElements(): ComponentDefinition[];
|
|
913
|
+
/**
|
|
914
|
+
* Get only block components (elements that live inside section slots)
|
|
915
|
+
*/
|
|
916
|
+
getBlocks(): ComponentDefinition[];
|
|
917
|
+
/**
|
|
918
|
+
* Get blocks available for a specific section type
|
|
919
|
+
* Returns theme blocks (global) + section blocks specific to this section type
|
|
920
|
+
*/
|
|
921
|
+
getBlocksForSectionType(sectionType: string): ComponentDefinition[];
|
|
922
|
+
/**
|
|
923
|
+
* Search components by name or tags
|
|
924
|
+
*/
|
|
925
|
+
search(query: string): ComponentDefinition[];
|
|
926
|
+
/**
|
|
927
|
+
* Generate default props for a type
|
|
928
|
+
*/
|
|
929
|
+
getDefaultProps(type: string): Record<string, unknown>;
|
|
930
|
+
/**
|
|
931
|
+
* Resolve a definition into ResolvedPreset entries.
|
|
932
|
+
* If it has presets, returns one entry per preset; otherwise one entry for the definition itself.
|
|
933
|
+
*/
|
|
934
|
+
resolvePresets(definition: ComponentDefinition): ResolvedPreset[];
|
|
935
|
+
/**
|
|
936
|
+
* Get all section definitions expanded into presets
|
|
937
|
+
*/
|
|
938
|
+
getSectionPresets(): ResolvedPreset[];
|
|
939
|
+
/**
|
|
940
|
+
* Get all block definitions expanded into presets
|
|
941
|
+
*/
|
|
942
|
+
getBlockPresets(): ResolvedPreset[];
|
|
943
|
+
/**
|
|
944
|
+
* Get block presets available for a specific section type
|
|
945
|
+
*/
|
|
946
|
+
getBlockPresetsForSectionType(sectionType: string): ResolvedPreset[];
|
|
947
|
+
/**
|
|
948
|
+
* Merge schema defaults with preset settings to produce final props
|
|
949
|
+
*/
|
|
950
|
+
getPresetProps(type: string, preset: ComponentPreset | null): Record<string, unknown>;
|
|
951
|
+
/**
|
|
952
|
+
* Validate props against the schema
|
|
953
|
+
*/
|
|
954
|
+
validateProps(type: string, props: Record<string, unknown>): Map<string, string>;
|
|
955
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ComponentRegistryService, never>;
|
|
956
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ComponentRegistryService>;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* Injection token for editor component definitions
|
|
961
|
+
*/
|
|
962
|
+
declare const EDITOR_COMPONENT_DEFINITIONS: InjectionToken<ComponentDefinition<Record<string, unknown>>[][]>;
|
|
963
|
+
/**
|
|
964
|
+
* Provider function to register editor components.
|
|
965
|
+
*
|
|
966
|
+
* @example
|
|
967
|
+
* ```typescript
|
|
968
|
+
* // app.config.ts
|
|
969
|
+
* export const appConfig: ApplicationConfig = {
|
|
970
|
+
* providers: [
|
|
971
|
+
* provideStore(),
|
|
972
|
+
* provideVisualEditorStore(),
|
|
973
|
+
* provideEditorComponents([
|
|
974
|
+
* heroSectionDefinition,
|
|
975
|
+
* textBlockDefinition,
|
|
976
|
+
* ]),
|
|
977
|
+
* ],
|
|
978
|
+
* };
|
|
979
|
+
* ```
|
|
980
|
+
*/
|
|
981
|
+
declare function provideEditorComponents(definitions: ComponentDefinition[]): EnvironmentProviders;
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Component that dynamically renders an EditorElement
|
|
985
|
+
* based on its type registered in the ComponentRegistry
|
|
986
|
+
*/
|
|
987
|
+
declare class DynamicRendererComponent {
|
|
988
|
+
private readonly registry;
|
|
989
|
+
private readonly viewContainerRef;
|
|
990
|
+
private readonly destroyRef;
|
|
991
|
+
/** Element to render */
|
|
992
|
+
readonly element: _angular_core.InputSignal<EditorElement>;
|
|
993
|
+
/** Additional context (sectionId, index, etc.) */
|
|
994
|
+
readonly context: _angular_core.InputSignal<Record<string, unknown>>;
|
|
995
|
+
/** Error state signal */
|
|
996
|
+
private _error;
|
|
997
|
+
error: () => boolean;
|
|
998
|
+
private componentRef;
|
|
999
|
+
private currentType;
|
|
1000
|
+
private currentAvailableInputs;
|
|
1001
|
+
private previousInputs;
|
|
1002
|
+
constructor();
|
|
1003
|
+
private renderComponent;
|
|
1004
|
+
private updateInputs;
|
|
1005
|
+
private setInputIfChanged;
|
|
1006
|
+
private getComponentInputs;
|
|
1007
|
+
private cleanup;
|
|
1008
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicRendererComponent, never>;
|
|
1009
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicRendererComponent, "lib-dynamic-renderer", never, { "element": { "alias": "element"; "required": true; "isSignal": true; }; "context": { "alias": "context"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Renders child elements within a specific slot
|
|
1014
|
+
*/
|
|
1015
|
+
declare class SlotRendererComponent {
|
|
1016
|
+
private readonly registry;
|
|
1017
|
+
/** Slot definition */
|
|
1018
|
+
readonly slot: _angular_core.InputSignal<SlotDefinition>;
|
|
1019
|
+
/** All children of the parent element */
|
|
1020
|
+
readonly children: _angular_core.InputSignal<EditorElement[]>;
|
|
1021
|
+
/** Parent element ID */
|
|
1022
|
+
readonly parentElementId: _angular_core.InputSignal<string>;
|
|
1023
|
+
/** Children filtered by slot name and constraints */
|
|
1024
|
+
readonly filteredChildren: _angular_core.Signal<EditorElement[]>;
|
|
1025
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SlotRendererComponent, never>;
|
|
1026
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SlotRendererComponent, "lib-slot-renderer", never, { "slot": { "alias": "slot"; "required": true; "isSignal": true; }; "children": { "alias": "children"; "required": true; "isSignal": true; }; "parentElementId": { "alias": "parentElementId"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Facade service that combines Store operations with ComponentRegistry
|
|
1031
|
+
*/
|
|
1032
|
+
declare class VisualEditorFacade {
|
|
1033
|
+
private readonly store;
|
|
1034
|
+
private readonly registry;
|
|
1035
|
+
private readonly pageService;
|
|
1036
|
+
readonly sections: _angular_core.Signal<EditorSection[]>;
|
|
1037
|
+
readonly selectedElement: _angular_core.Signal<EditorElement | null>;
|
|
1038
|
+
readonly selectedSection: _angular_core.Signal<EditorSection | null>;
|
|
1039
|
+
readonly canUndo: _angular_core.Signal<boolean>;
|
|
1040
|
+
readonly canRedo: _angular_core.Signal<boolean>;
|
|
1041
|
+
readonly isDragging: _angular_core.Signal<boolean>;
|
|
1042
|
+
readonly selectedBlock: _angular_core.Signal<EditorElement | null>;
|
|
1043
|
+
readonly selectedBlockSlotName: _angular_core.Signal<string | null>;
|
|
1044
|
+
readonly currentPage: _angular_core.Signal<PageContext | null>;
|
|
1045
|
+
readonly currentPageId: _angular_core.Signal<string | null>;
|
|
1046
|
+
readonly isDirty: _angular_core.Signal<boolean>;
|
|
1047
|
+
readonly isPageLoaded: _angular_core.Signal<boolean>;
|
|
1048
|
+
readonly selectedElementDefinition: _angular_core.Signal<ComponentDefinition<Record<string, unknown>> | null>;
|
|
1049
|
+
readonly selectedSectionDefinition: _angular_core.Signal<ComponentDefinition<Record<string, unknown>> | null>;
|
|
1050
|
+
readonly selectedBlockDefinition: _angular_core.Signal<ComponentDefinition<Record<string, unknown>> | null>;
|
|
1051
|
+
readonly availableSections: _angular_core.Signal<ComponentDefinition<Record<string, unknown>>[]>;
|
|
1052
|
+
readonly availableElements: _angular_core.Signal<ComponentDefinition<Record<string, unknown>>[]>;
|
|
1053
|
+
readonly availableBlocks: _angular_core.Signal<ComponentDefinition<Record<string, unknown>>[]>;
|
|
1054
|
+
readonly availableSectionPresets: _angular_core.Signal<ResolvedPreset[]>;
|
|
1055
|
+
readonly availableBlockPresets: _angular_core.Signal<ResolvedPreset[]>;
|
|
1056
|
+
/**
|
|
1057
|
+
* Create a new element with default props from registry
|
|
1058
|
+
*/
|
|
1059
|
+
createElementWithDefaults(type: string, overrides?: Partial<EditorElement>): EditorElement;
|
|
1060
|
+
/**
|
|
1061
|
+
* Create a new section with default props from registry
|
|
1062
|
+
*/
|
|
1063
|
+
createSectionWithDefaults(type: string, overrides?: Partial<EditorSection>): EditorSection;
|
|
1064
|
+
/**
|
|
1065
|
+
* Add a section to the editor
|
|
1066
|
+
*/
|
|
1067
|
+
addSection(type: string, index?: number): void;
|
|
1068
|
+
/**
|
|
1069
|
+
* Add an element to a section
|
|
1070
|
+
*/
|
|
1071
|
+
addElement(sectionId: string, type: string, index?: number): void;
|
|
1072
|
+
/**
|
|
1073
|
+
* Remove a section
|
|
1074
|
+
*/
|
|
1075
|
+
removeSection(sectionId: string): void;
|
|
1076
|
+
/**
|
|
1077
|
+
* Remove an element
|
|
1078
|
+
*/
|
|
1079
|
+
removeElement(sectionId: string, elementId: string): void;
|
|
1080
|
+
/**
|
|
1081
|
+
* Move a section to a new index
|
|
1082
|
+
*/
|
|
1083
|
+
moveSection(sectionId: string, newIndex: number): void;
|
|
1084
|
+
/**
|
|
1085
|
+
* Move an element within or between sections
|
|
1086
|
+
*/
|
|
1087
|
+
moveElement(sourceSectionId: string, targetSectionId: string, elementId: string, newIndex: number): void;
|
|
1088
|
+
/**
|
|
1089
|
+
* Rename a section (set adminLabel)
|
|
1090
|
+
*/
|
|
1091
|
+
renameSection(sectionId: string, adminLabel: string): void;
|
|
1092
|
+
/**
|
|
1093
|
+
* Rename a block (set adminLabel)
|
|
1094
|
+
*/
|
|
1095
|
+
renameBlock(sectionId: string, elementId: string, adminLabel: string): void;
|
|
1096
|
+
/**
|
|
1097
|
+
* Create a block element with default props and slotName
|
|
1098
|
+
*/
|
|
1099
|
+
createBlockWithDefaults(type: string, slotName: string, overrides?: Partial<EditorElement>): EditorElement;
|
|
1100
|
+
/**
|
|
1101
|
+
* Add a block to a section's slot
|
|
1102
|
+
*/
|
|
1103
|
+
addBlock(sectionId: string, slotName: string, type: string, index?: number): void;
|
|
1104
|
+
/**
|
|
1105
|
+
* Add a section from a resolved preset.
|
|
1106
|
+
* Merges preset settings into default props and creates pre-configured blocks.
|
|
1107
|
+
*/
|
|
1108
|
+
addSectionFromPreset(resolvedPreset: ResolvedPreset, index?: number): void;
|
|
1109
|
+
/**
|
|
1110
|
+
* Add a block from a resolved preset to a section's slot.
|
|
1111
|
+
*/
|
|
1112
|
+
addBlockFromPreset(sectionId: string, slotName: string, resolvedPreset: ResolvedPreset, index?: number): void;
|
|
1113
|
+
/**
|
|
1114
|
+
* Generate EditorElement[] from a preset's blocks configuration
|
|
1115
|
+
*/
|
|
1116
|
+
private createPresetBlocks;
|
|
1117
|
+
/**
|
|
1118
|
+
* Generate children for blocks that have slots, from preset block configs
|
|
1119
|
+
*/
|
|
1120
|
+
private createPresetBlockChildren;
|
|
1121
|
+
/**
|
|
1122
|
+
* Remove a block from a section
|
|
1123
|
+
*/
|
|
1124
|
+
removeBlock(sectionId: string, elementId: string): void;
|
|
1125
|
+
/**
|
|
1126
|
+
* Move a block within a section (can change slots)
|
|
1127
|
+
*/
|
|
1128
|
+
moveBlock(sectionId: string, elementId: string, targetSlotName: string, newIndex: number): void;
|
|
1129
|
+
/**
|
|
1130
|
+
* Check if a section type can be duplicated
|
|
1131
|
+
*/
|
|
1132
|
+
isSectionDuplicable(type: string): boolean;
|
|
1133
|
+
/**
|
|
1134
|
+
* Check if a block type can be duplicated
|
|
1135
|
+
*/
|
|
1136
|
+
isBlockDuplicable(type: string): boolean;
|
|
1137
|
+
/**
|
|
1138
|
+
* Duplicate a section (deep clone with new IDs)
|
|
1139
|
+
*/
|
|
1140
|
+
duplicateSection(sectionId: string): void;
|
|
1141
|
+
/**
|
|
1142
|
+
* Duplicate a block within a section
|
|
1143
|
+
*/
|
|
1144
|
+
duplicateBlock(sectionId: string, elementId: string): void;
|
|
1145
|
+
/**
|
|
1146
|
+
* Duplicate a nested block
|
|
1147
|
+
*/
|
|
1148
|
+
duplicateNestedBlock(sectionId: string, parentPath: string[], elementId: string): void;
|
|
1149
|
+
/**
|
|
1150
|
+
* Update block props with validation (works for both direct and nested blocks)
|
|
1151
|
+
*/
|
|
1152
|
+
updateBlockProps(sectionId: string, elementId: string, props: Record<string, unknown>): void;
|
|
1153
|
+
/**
|
|
1154
|
+
* Get blocks for a specific slot in a section
|
|
1155
|
+
*/
|
|
1156
|
+
getBlocksForSlot(sectionId: string, slotName: string): EditorElement[];
|
|
1157
|
+
/**
|
|
1158
|
+
* Get allowed block types for a slot
|
|
1159
|
+
*/
|
|
1160
|
+
getAllowedBlocksForSlot(sectionType: string, slotName: string): ComponentDefinition[];
|
|
1161
|
+
/**
|
|
1162
|
+
* Check if a component type has slots (can contain nested blocks)
|
|
1163
|
+
*/
|
|
1164
|
+
hasSlots(type: string): boolean;
|
|
1165
|
+
/**
|
|
1166
|
+
* Get slots for a block type
|
|
1167
|
+
*/
|
|
1168
|
+
getBlockSlots(type: string): SlotDefinition[];
|
|
1169
|
+
/**
|
|
1170
|
+
* Check if adding a nested block is allowed (max 12 levels)
|
|
1171
|
+
*/
|
|
1172
|
+
canAddNestedBlock(parentPath: string[]): boolean;
|
|
1173
|
+
/**
|
|
1174
|
+
* Add a nested block to a parent element
|
|
1175
|
+
*/
|
|
1176
|
+
addNestedBlock(sectionId: string, parentPath: string[], slotName: string, type: string, index?: number): void;
|
|
1177
|
+
/**
|
|
1178
|
+
* Remove a nested block from a parent element
|
|
1179
|
+
*/
|
|
1180
|
+
removeNestedBlock(sectionId: string, parentPath: string[], elementId: string): void;
|
|
1181
|
+
/**
|
|
1182
|
+
* Update nested block props
|
|
1183
|
+
*/
|
|
1184
|
+
updateNestedBlockProps(sectionId: string, parentPath: string[], elementId: string, props: Record<string, unknown>): void;
|
|
1185
|
+
/**
|
|
1186
|
+
* Move a nested block within its parent
|
|
1187
|
+
*/
|
|
1188
|
+
moveNestedBlock(sectionId: string, parentPath: string[], elementId: string, targetSlotName: string, newIndex: number): void;
|
|
1189
|
+
/**
|
|
1190
|
+
* Reparent a block: move it from one parent/section to another
|
|
1191
|
+
*/
|
|
1192
|
+
reparentBlock(sourceSectionId: string, sourceParentPath: string[], elementId: string, targetSectionId: string, targetParentPath: string[], targetSlotName: string, targetIndex: number): void;
|
|
1193
|
+
/**
|
|
1194
|
+
* Get children of an element filtered by slot
|
|
1195
|
+
*/
|
|
1196
|
+
getElementChildren(element: EditorElement, slotName?: string): EditorElement[];
|
|
1197
|
+
/**
|
|
1198
|
+
* Get allowed blocks for a nested slot
|
|
1199
|
+
*/
|
|
1200
|
+
getAllowedBlocksForNestedSlot(parentType: string, slotName: string): ComponentDefinition[];
|
|
1201
|
+
/**
|
|
1202
|
+
* Select an element
|
|
1203
|
+
*/
|
|
1204
|
+
selectElement(sectionId: string | null, elementId: string | null): void;
|
|
1205
|
+
/**
|
|
1206
|
+
* Clear selection
|
|
1207
|
+
*/
|
|
1208
|
+
clearSelection(): void;
|
|
1209
|
+
/**
|
|
1210
|
+
* Update element props with validation
|
|
1211
|
+
*/
|
|
1212
|
+
updateElementProps(sectionId: string, elementId: string, props: Record<string, unknown>): void;
|
|
1213
|
+
/**
|
|
1214
|
+
* Update section props with validation
|
|
1215
|
+
*/
|
|
1216
|
+
updateSectionProps(sectionId: string, props: Record<string, unknown>): void;
|
|
1217
|
+
/**
|
|
1218
|
+
* Undo last action
|
|
1219
|
+
*/
|
|
1220
|
+
undo(): void;
|
|
1221
|
+
/**
|
|
1222
|
+
* Redo last undone action
|
|
1223
|
+
*/
|
|
1224
|
+
redo(): void;
|
|
1225
|
+
/**
|
|
1226
|
+
* Load sections into the editor
|
|
1227
|
+
*/
|
|
1228
|
+
loadSections(sections: EditorSection[]): void;
|
|
1229
|
+
/**
|
|
1230
|
+
* Reset editor to initial state
|
|
1231
|
+
*/
|
|
1232
|
+
resetEditor(): void;
|
|
1233
|
+
/**
|
|
1234
|
+
* Get component definition by type
|
|
1235
|
+
*/
|
|
1236
|
+
getDefinition(type: string): ComponentDefinition | undefined;
|
|
1237
|
+
/**
|
|
1238
|
+
* Search components
|
|
1239
|
+
*/
|
|
1240
|
+
searchComponents(query: string): ComponentDefinition[];
|
|
1241
|
+
/**
|
|
1242
|
+
* Get all pages (summaries)
|
|
1243
|
+
*/
|
|
1244
|
+
getPages(): Observable<PageSummary[]>;
|
|
1245
|
+
/**
|
|
1246
|
+
* Get a page by ID and load it into the editor
|
|
1247
|
+
*/
|
|
1248
|
+
getPage(id: string): Observable<Page>;
|
|
1249
|
+
/**
|
|
1250
|
+
* Get a published page by slug (for public rendering)
|
|
1251
|
+
*/
|
|
1252
|
+
getPublishedPageBySlug(slug: string): Observable<Page>;
|
|
1253
|
+
/**
|
|
1254
|
+
* Load a page into the editor
|
|
1255
|
+
*/
|
|
1256
|
+
loadPage(page: Page): void;
|
|
1257
|
+
/**
|
|
1258
|
+
* Create a new page
|
|
1259
|
+
*/
|
|
1260
|
+
createPage(request: CreatePageRequest): Observable<Page>;
|
|
1261
|
+
/**
|
|
1262
|
+
* Save current editor state to a page
|
|
1263
|
+
*/
|
|
1264
|
+
savePage(pageId: string): Observable<Page>;
|
|
1265
|
+
/**
|
|
1266
|
+
* Update page metadata (title, slug, etc.)
|
|
1267
|
+
*/
|
|
1268
|
+
updatePageMetadata(pageId: string, metadata: Partial<PageContext>): Observable<Page>;
|
|
1269
|
+
/**
|
|
1270
|
+
* Delete a page
|
|
1271
|
+
*/
|
|
1272
|
+
deletePage(id: string): Observable<void>;
|
|
1273
|
+
/**
|
|
1274
|
+
* Publish a page
|
|
1275
|
+
*/
|
|
1276
|
+
publishPage(pageId: string): Observable<Page>;
|
|
1277
|
+
/**
|
|
1278
|
+
* Unpublish a page
|
|
1279
|
+
*/
|
|
1280
|
+
unpublishPage(pageId: string): Observable<Page>;
|
|
1281
|
+
/**
|
|
1282
|
+
* Duplicate a page
|
|
1283
|
+
*/
|
|
1284
|
+
duplicatePage(id: string): Observable<Page>;
|
|
1285
|
+
/**
|
|
1286
|
+
* Clear the current page from editor
|
|
1287
|
+
*/
|
|
1288
|
+
clearPage(): void;
|
|
1289
|
+
/**
|
|
1290
|
+
* Mark editor as dirty (has unsaved changes)
|
|
1291
|
+
*/
|
|
1292
|
+
markDirty(): void;
|
|
1293
|
+
/**
|
|
1294
|
+
* Mark editor as clean (no unsaved changes)
|
|
1295
|
+
*/
|
|
1296
|
+
markClean(): void;
|
|
1297
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<VisualEditorFacade, never>;
|
|
1298
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<VisualEditorFacade>;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
type DropZone = 'before' | 'inside' | 'after';
|
|
1302
|
+
type DragItemKind = 'section' | 'block';
|
|
1303
|
+
interface DragItem {
|
|
1304
|
+
kind: DragItemKind;
|
|
1305
|
+
elementId: string;
|
|
1306
|
+
elementType: string;
|
|
1307
|
+
sectionId: string;
|
|
1308
|
+
parentPath: string[];
|
|
1309
|
+
slotName?: string;
|
|
1310
|
+
sourceIndex: number;
|
|
1311
|
+
}
|
|
1312
|
+
interface DropTarget {
|
|
1313
|
+
kind: DragItemKind;
|
|
1314
|
+
sectionId: string;
|
|
1315
|
+
parentPath: string[];
|
|
1316
|
+
slotName: string;
|
|
1317
|
+
index: number;
|
|
1318
|
+
depth: number;
|
|
1319
|
+
zone: DropZone;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* Context for a block in the tree hierarchy
|
|
1324
|
+
*/
|
|
1325
|
+
interface BlockTreeContext {
|
|
1326
|
+
sectionId: string;
|
|
1327
|
+
parentPath: string[];
|
|
1328
|
+
depth: number;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Target information for opening the block picker
|
|
1332
|
+
*/
|
|
1333
|
+
interface BlockPickerTarget {
|
|
1334
|
+
sectionId: string;
|
|
1335
|
+
parentPath: string[];
|
|
1336
|
+
parentType: string;
|
|
1337
|
+
slots: SlotDefinition[];
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* Recursive component for rendering a block in the sidebar tree
|
|
1341
|
+
* Supports nested blocks with expand/collapse functionality
|
|
1342
|
+
*/
|
|
1343
|
+
declare class BlockTreeItemComponent {
|
|
1344
|
+
readonly facade: VisualEditorFacade;
|
|
1345
|
+
private readonly dndService;
|
|
1346
|
+
private readonly sanitizer;
|
|
1347
|
+
private readonly treeBlock;
|
|
1348
|
+
readonly block: _angular_core.InputSignal<EditorElement>;
|
|
1349
|
+
readonly context: _angular_core.InputSignal<BlockTreeContext>;
|
|
1350
|
+
readonly index: _angular_core.InputSignal<number>;
|
|
1351
|
+
readonly totalSiblings: _angular_core.InputSignal<number>;
|
|
1352
|
+
readonly expandAll: _angular_core.InputSignal<boolean>;
|
|
1353
|
+
readonly selectBlock: _angular_core.OutputEmitterRef<{
|
|
1354
|
+
block: EditorElement;
|
|
1355
|
+
context: BlockTreeContext;
|
|
1356
|
+
}>;
|
|
1357
|
+
readonly deleteBlock: _angular_core.OutputEmitterRef<{
|
|
1358
|
+
block: EditorElement;
|
|
1359
|
+
context: BlockTreeContext;
|
|
1360
|
+
}>;
|
|
1361
|
+
readonly duplicateBlock: _angular_core.OutputEmitterRef<{
|
|
1362
|
+
block: EditorElement;
|
|
1363
|
+
context: BlockTreeContext;
|
|
1364
|
+
}>;
|
|
1365
|
+
readonly moveBlock: _angular_core.OutputEmitterRef<{
|
|
1366
|
+
block: EditorElement;
|
|
1367
|
+
context: BlockTreeContext;
|
|
1368
|
+
newIndex: number;
|
|
1369
|
+
}>;
|
|
1370
|
+
readonly openBlockPicker: _angular_core.OutputEmitterRef<BlockPickerTarget>;
|
|
1371
|
+
private readonly expanded;
|
|
1372
|
+
readonly dropZone: _angular_core.WritableSignal<DropZone | null>;
|
|
1373
|
+
readonly isDragSource: _angular_core.Signal<boolean>;
|
|
1374
|
+
readonly blockHasSlots: _angular_core.Signal<boolean>;
|
|
1375
|
+
readonly blockSlots: _angular_core.Signal<SlotDefinition[]>;
|
|
1376
|
+
readonly children: _angular_core.Signal<EditorElement[]>;
|
|
1377
|
+
readonly childContext: _angular_core.Signal<BlockTreeContext>;
|
|
1378
|
+
readonly blockIcon: _angular_core.Signal<SafeHtml>;
|
|
1379
|
+
readonly blockName: _angular_core.Signal<string>;
|
|
1380
|
+
readonly duplicable: _angular_core.Signal<boolean>;
|
|
1381
|
+
readonly canAddMore: _angular_core.Signal<boolean>;
|
|
1382
|
+
isExpanded(): boolean;
|
|
1383
|
+
toggleExpand(event: Event): void;
|
|
1384
|
+
hasSlots(): boolean;
|
|
1385
|
+
getBlockSlots(): SlotDefinition[];
|
|
1386
|
+
onDuplicate(event: Event): void;
|
|
1387
|
+
onSelect(event: Event): void;
|
|
1388
|
+
onDelete(event: Event): void;
|
|
1389
|
+
onMoveUp(event: Event): void;
|
|
1390
|
+
onMoveDown(event: Event): void;
|
|
1391
|
+
onAddBlock(event: Event): void;
|
|
1392
|
+
onDragStart(event: DragEvent): void;
|
|
1393
|
+
onDragEnd(event: DragEvent): void;
|
|
1394
|
+
onDragOver(event: DragEvent): void;
|
|
1395
|
+
onDragLeave(event: DragEvent): void;
|
|
1396
|
+
onDrop(event: DragEvent): void;
|
|
1397
|
+
onDragHandleKeydown(event: KeyboardEvent): void;
|
|
1398
|
+
private buildDropTarget;
|
|
1399
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<BlockTreeItemComponent, never>;
|
|
1400
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<BlockTreeItemComponent, "lib-block-tree-item", never, { "block": { "alias": "block"; "required": true; "isSignal": true; }; "context": { "alias": "context"; "required": true; "isSignal": true; }; "index": { "alias": "index"; "required": true; "isSignal": true; }; "totalSiblings": { "alias": "totalSiblings"; "required": true; "isSignal": true; }; "expandAll": { "alias": "expandAll"; "required": false; "isSignal": true; }; }, { "selectBlock": "selectBlock"; "deleteBlock": "deleteBlock"; "duplicateBlock": "duplicateBlock"; "moveBlock": "moveBlock"; "openBlockPicker": "openBlockPicker"; }, never, never, true, never>;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* Main Visual Editor component
|
|
1405
|
+
* Provides a complete editing interface with:
|
|
1406
|
+
* - Sidebar with hierarchical tree view
|
|
1407
|
+
* - Canvas with live preview
|
|
1408
|
+
* - Properties panel for editing section/block properties
|
|
1409
|
+
*/
|
|
1410
|
+
declare class VisualEditorComponent implements OnInit, OnDestroy {
|
|
1411
|
+
readonly facade: VisualEditorFacade;
|
|
1412
|
+
private readonly registry;
|
|
1413
|
+
private readonly navigation;
|
|
1414
|
+
private readonly loadingStrategy;
|
|
1415
|
+
private readonly config;
|
|
1416
|
+
private readonly dndService;
|
|
1417
|
+
private readonly sanitizer;
|
|
1418
|
+
private readonly destroy$;
|
|
1419
|
+
readonly showBackButton: _angular_core.Signal<boolean>;
|
|
1420
|
+
readonly showPublishButtons: _angular_core.Signal<boolean>;
|
|
1421
|
+
readonly showSaveButton: _angular_core.Signal<boolean>;
|
|
1422
|
+
readonly isPreviewMode: _angular_core.WritableSignal<boolean>;
|
|
1423
|
+
readonly editorContext: _angular_core.Signal<{
|
|
1424
|
+
isEditor: boolean;
|
|
1425
|
+
}>;
|
|
1426
|
+
private readonly canvasEl;
|
|
1427
|
+
readonly propertiesTab: _angular_core.WritableSignal<"props" | "blocks">;
|
|
1428
|
+
readonly expandedGroups: _angular_core.WritableSignal<Set<string>>;
|
|
1429
|
+
readonly expandedSections: _angular_core.WritableSignal<Set<string>>;
|
|
1430
|
+
readonly allBlocksExpanded: _angular_core.WritableSignal<Set<string>>;
|
|
1431
|
+
readonly showSectionPicker: _angular_core.WritableSignal<boolean>;
|
|
1432
|
+
readonly blockPickerSection: _angular_core.WritableSignal<EditorSection | null>;
|
|
1433
|
+
readonly nestedBlockPickerTarget: _angular_core.WritableSignal<BlockPickerTarget | null>;
|
|
1434
|
+
readonly filePickerOpen: _angular_core.WritableSignal<boolean>;
|
|
1435
|
+
readonly filePickerMediaType: _angular_core.WritableSignal<"IMAGE" | "VIDEO">;
|
|
1436
|
+
readonly filePickerTargetKey: _angular_core.WritableSignal<string>;
|
|
1437
|
+
readonly filePickerContext: _angular_core.WritableSignal<"section" | "block">;
|
|
1438
|
+
readonly filePickerCurrentValue: _angular_core.Signal<string>;
|
|
1439
|
+
readonly isSaving: _angular_core.WritableSignal<boolean>;
|
|
1440
|
+
readonly isPublishing: _angular_core.WritableSignal<boolean>;
|
|
1441
|
+
readonly isLoading: _angular_core.WritableSignal<boolean>;
|
|
1442
|
+
readonly searchQuery: _angular_core.WritableSignal<string>;
|
|
1443
|
+
readonly sectionPickerSearch: _angular_core.WritableSignal<string>;
|
|
1444
|
+
readonly blockPickerSearch: _angular_core.WritableSignal<string>;
|
|
1445
|
+
readonly nestedBlockPickerSearch: _angular_core.WritableSignal<string>;
|
|
1446
|
+
readonly sectionDropZone: _angular_core.WritableSignal<string | null>;
|
|
1447
|
+
readonly dndAnnouncement: _angular_core.WritableSignal<string>;
|
|
1448
|
+
private sectionAutoExpandTimer;
|
|
1449
|
+
readonly filteredSections: _angular_core.Signal<EditorSection[]>;
|
|
1450
|
+
readonly filteredAvailableSectionPresets: _angular_core.Signal<ResolvedPreset[]>;
|
|
1451
|
+
readonly groupedSectionPresets: _angular_core.Signal<{
|
|
1452
|
+
category: string;
|
|
1453
|
+
presets: ResolvedPreset[];
|
|
1454
|
+
}[]>;
|
|
1455
|
+
readonly filteredBlockPresetsForSection: _angular_core.Signal<ResolvedPreset[]>;
|
|
1456
|
+
readonly filteredBlockPresetsForNestedSlot: _angular_core.Signal<ResolvedPreset[]>;
|
|
1457
|
+
private readonly sectionIconMap;
|
|
1458
|
+
private readonly blockIconMap;
|
|
1459
|
+
readonly selectedBlockDefinition: _angular_core.Signal<ComponentDefinition<Record<string, unknown>> | null>;
|
|
1460
|
+
private readonly nameInput;
|
|
1461
|
+
readonly isEditingName: _angular_core.WritableSignal<boolean>;
|
|
1462
|
+
readonly editingNameValue: _angular_core.WritableSignal<string>;
|
|
1463
|
+
getSelectedDisplayName(def: ComponentDefinition): string;
|
|
1464
|
+
getSelectedDefaultName(def: ComponentDefinition): string;
|
|
1465
|
+
startEditingName(): void;
|
|
1466
|
+
saveEditingName(event: Event): void;
|
|
1467
|
+
cancelEditingName(): void;
|
|
1468
|
+
ngOnInit(): void;
|
|
1469
|
+
ngOnDestroy(): void;
|
|
1470
|
+
goBack(): void;
|
|
1471
|
+
savePage(): void;
|
|
1472
|
+
publishPage(): void;
|
|
1473
|
+
unpublishPage(): void;
|
|
1474
|
+
private readonly defaultSectionIcon;
|
|
1475
|
+
private readonly defaultBlockIcon;
|
|
1476
|
+
private toSafeIcon;
|
|
1477
|
+
getIcon(def: ComponentDefinition): SafeHtml;
|
|
1478
|
+
getBlockIcon(def: ComponentDefinition): SafeHtml;
|
|
1479
|
+
getBlockIconByType(type: string): SafeHtml;
|
|
1480
|
+
getSectionIcon(type: string): SafeHtml;
|
|
1481
|
+
isSectionExpanded(sectionId: string): boolean;
|
|
1482
|
+
isAllBlocksExpanded(sectionId: string): boolean;
|
|
1483
|
+
toggleSectionExpand(sectionId: string, event: Event): void;
|
|
1484
|
+
toggleGroup(entityId: string, group: string): void;
|
|
1485
|
+
isGroupCollapsed(entityId: string, group: string): boolean;
|
|
1486
|
+
getSectionBlocks(section: EditorSection): EditorElement[];
|
|
1487
|
+
private readonly rootBlockContextCache;
|
|
1488
|
+
private readonly emptyPath;
|
|
1489
|
+
getRootBlockContext(sectionId: string): BlockTreeContext;
|
|
1490
|
+
onSearchInput(event: Event): void;
|
|
1491
|
+
clearSearch(): void;
|
|
1492
|
+
isSectionDragSource(sectionId: string): boolean;
|
|
1493
|
+
onSectionDragStart(section: EditorSection, index: number, event: DragEvent): void;
|
|
1494
|
+
onSectionDragEnd(event: DragEvent): void;
|
|
1495
|
+
onSectionDragOver(section: EditorSection, index: number, event: DragEvent): void;
|
|
1496
|
+
onSectionDragLeave(event: DragEvent): void;
|
|
1497
|
+
onSectionDrop(event: DragEvent): void;
|
|
1498
|
+
onSectionDragHandleKeydown(sectionId: string, index: number, event: KeyboardEvent): void;
|
|
1499
|
+
onSectionContentDragOver(section: EditorSection, event: DragEvent): void;
|
|
1500
|
+
onSectionContentDragLeave(event: DragEvent): void;
|
|
1501
|
+
onSectionContentDrop(event: DragEvent): void;
|
|
1502
|
+
private startAutoExpandTimer;
|
|
1503
|
+
private clearAutoExpandTimer;
|
|
1504
|
+
private scrollToCanvasElement;
|
|
1505
|
+
/** Return the element itself if it has a box, otherwise its first laid-out child. */
|
|
1506
|
+
private resolveScrollTarget;
|
|
1507
|
+
private scrollToCanvasSection;
|
|
1508
|
+
onSectionPickerSearch(event: Event): void;
|
|
1509
|
+
onBlockPickerSearch(event: Event): void;
|
|
1510
|
+
toggleSectionPicker(): void;
|
|
1511
|
+
openBlockPicker(section: EditorSection, event: Event): void;
|
|
1512
|
+
closeBlockPicker(): void;
|
|
1513
|
+
onOpenNestedBlockPicker(target: BlockPickerTarget): void;
|
|
1514
|
+
closeNestedBlockPicker(): void;
|
|
1515
|
+
onNestedBlockPickerSearch(event: Event): void;
|
|
1516
|
+
addNestedBlock(blockType: string): void;
|
|
1517
|
+
onBlockSelect(event: {
|
|
1518
|
+
block: EditorElement;
|
|
1519
|
+
context: BlockTreeContext;
|
|
1520
|
+
}): void;
|
|
1521
|
+
onBlockDelete(event: {
|
|
1522
|
+
block: EditorElement;
|
|
1523
|
+
context: BlockTreeContext;
|
|
1524
|
+
}): void;
|
|
1525
|
+
onBlockMove(event: {
|
|
1526
|
+
block: EditorElement;
|
|
1527
|
+
context: BlockTreeContext;
|
|
1528
|
+
newIndex: number;
|
|
1529
|
+
}): void;
|
|
1530
|
+
onBlockDuplicate(event: {
|
|
1531
|
+
block: EditorElement;
|
|
1532
|
+
context: BlockTreeContext;
|
|
1533
|
+
}): void;
|
|
1534
|
+
duplicateSection(sectionId: string, event: Event): void;
|
|
1535
|
+
duplicateBlock(block: EditorElement, event: Event): void;
|
|
1536
|
+
addBlockToSection(section: EditorSection, blockType: string): void;
|
|
1537
|
+
getSectionName(section: EditorSection): string;
|
|
1538
|
+
getBlockName(block: EditorElement): string;
|
|
1539
|
+
addSection(type: string): void;
|
|
1540
|
+
addSectionFromPreset(rp: ResolvedPreset): void;
|
|
1541
|
+
addBlockToSectionFromPreset(section: EditorSection, rp: ResolvedPreset): void;
|
|
1542
|
+
addNestedBlockFromPreset(rp: ResolvedPreset): void;
|
|
1543
|
+
getSectionPresetIcon(rp: ResolvedPreset): SafeHtml;
|
|
1544
|
+
getBlockPresetIcon(rp: ResolvedPreset): SafeHtml;
|
|
1545
|
+
selectSection(section: EditorSection, event: Event): void;
|
|
1546
|
+
selectBlock(block: EditorElement): void;
|
|
1547
|
+
deleteSection(sectionId: string, event: Event): void;
|
|
1548
|
+
deleteBlock(block: EditorElement, event: Event): void;
|
|
1549
|
+
deleteSelectedBlock(): void;
|
|
1550
|
+
moveUp(sectionId: string, currentIndex: number, event: Event): void;
|
|
1551
|
+
moveDown(sectionId: string, currentIndex: number, event: Event): void;
|
|
1552
|
+
moveBlockUp(block: EditorElement, slotName: string, currentIndex: number, event: Event): void;
|
|
1553
|
+
moveBlockDown(block: EditorElement, slotName: string, currentIndex: number, event: Event): void;
|
|
1554
|
+
togglePreview(): void;
|
|
1555
|
+
getSectionSlots(): SlotDefinition[];
|
|
1556
|
+
getBlocksForSlot(slotName: string): EditorElement[];
|
|
1557
|
+
getBlockCount(): number;
|
|
1558
|
+
getPropertyGroups(def: ComponentDefinition): string[];
|
|
1559
|
+
getPropsForGroup(def: ComponentDefinition, group: string): Array<{
|
|
1560
|
+
key: string;
|
|
1561
|
+
schema: (typeof def.props)[string];
|
|
1562
|
+
}>;
|
|
1563
|
+
getPropertyValue(key: string): string;
|
|
1564
|
+
updateProperty(key: string, event: Event): void;
|
|
1565
|
+
getBlockPropertyGroups(): string[];
|
|
1566
|
+
getBlockPropsForGroup(group: string): Array<{
|
|
1567
|
+
key: string;
|
|
1568
|
+
schema: ComponentDefinition['props'][string];
|
|
1569
|
+
}>;
|
|
1570
|
+
getBlockPropertyValue(key: string): string;
|
|
1571
|
+
updateBlockProperty(key: string, event: Event): void;
|
|
1572
|
+
updateBlockBooleanProperty(key: string, event: Event): void;
|
|
1573
|
+
openFilePicker(mediaType: 'IMAGE' | 'VIDEO', key: string, context: 'block' | 'section'): void;
|
|
1574
|
+
closeFilePicker(): void;
|
|
1575
|
+
onFileSelected(url: string): void;
|
|
1576
|
+
clearBlockProperty(key: string): void;
|
|
1577
|
+
clearSectionProperty(key: string): void;
|
|
1578
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<VisualEditorComponent, never>;
|
|
1579
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<VisualEditorComponent, "lib-visual-editor", never, {}, {}, never, never, true, never>;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
interface ShopifyFile {
|
|
1583
|
+
id: string;
|
|
1584
|
+
alt: string;
|
|
1585
|
+
url: string;
|
|
1586
|
+
filename: string;
|
|
1587
|
+
mediaType: 'IMAGE' | 'VIDEO';
|
|
1588
|
+
mimeType: string;
|
|
1589
|
+
width?: number;
|
|
1590
|
+
height?: number;
|
|
1591
|
+
createdAt: string;
|
|
1592
|
+
}
|
|
1593
|
+
interface ShopifyFilesPage {
|
|
1594
|
+
files: ShopifyFile[];
|
|
1595
|
+
pageInfo: {
|
|
1596
|
+
hasNextPage: boolean;
|
|
1597
|
+
endCursor: string | null;
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
declare const FILES_QUERY = "\n query GetFiles($first: Int!, $after: String, $query: String) {\n files(first: $first, after: $after, query: $query) {\n edges {\n node {\n ... on MediaImage {\n id\n alt\n createdAt\n mimeType\n image {\n url\n width\n height\n }\n originalSource {\n fileSize\n }\n }\n ... on Video {\n id\n alt\n createdAt\n filename\n originalSource {\n mimeType\n url\n }\n sources {\n url\n mimeType\n width\n height\n }\n }\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n";
|
|
1601
|
+
declare class ShopifyFilesService {
|
|
1602
|
+
private readonly client;
|
|
1603
|
+
getFiles(mediaType: 'IMAGE' | 'VIDEO', search?: string, first?: number, after?: string): Observable<ShopifyFilesPage>;
|
|
1604
|
+
private mapNode;
|
|
1605
|
+
private extractFilename;
|
|
1606
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopifyFilesService, never>;
|
|
1607
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShopifyFilesService>;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
declare class ShopifyFilePickerComponent implements OnInit, OnDestroy {
|
|
1611
|
+
readonly mediaType: _angular_core.InputSignal<"IMAGE" | "VIDEO">;
|
|
1612
|
+
readonly currentValue: _angular_core.InputSignal<string>;
|
|
1613
|
+
readonly fileSelected: _angular_core.OutputEmitterRef<string>;
|
|
1614
|
+
readonly closed: _angular_core.OutputEmitterRef<void>;
|
|
1615
|
+
private readonly filesService;
|
|
1616
|
+
private readonly destroy$;
|
|
1617
|
+
private readonly searchSubject;
|
|
1618
|
+
private readonly searchInput;
|
|
1619
|
+
private readonly scrollContainer;
|
|
1620
|
+
readonly files: _angular_core.WritableSignal<ShopifyFile[]>;
|
|
1621
|
+
readonly selectedFile: _angular_core.WritableSignal<ShopifyFile | null>;
|
|
1622
|
+
readonly isLoading: _angular_core.WritableSignal<boolean>;
|
|
1623
|
+
readonly error: _angular_core.WritableSignal<string | null>;
|
|
1624
|
+
readonly searchTerm: _angular_core.WritableSignal<string>;
|
|
1625
|
+
private endCursor;
|
|
1626
|
+
private hasNextPage;
|
|
1627
|
+
ngOnInit(): void;
|
|
1628
|
+
ngOnDestroy(): void;
|
|
1629
|
+
loadFiles(): void;
|
|
1630
|
+
onSearchInput(event: Event): void;
|
|
1631
|
+
onScroll(): void;
|
|
1632
|
+
selectFile(file: ShopifyFile): void;
|
|
1633
|
+
selectAndConfirm(file: ShopifyFile): void;
|
|
1634
|
+
confirmSelection(): void;
|
|
1635
|
+
close(): void;
|
|
1636
|
+
onBackdropClick(event: Event): void;
|
|
1637
|
+
getThumbnailUrl(url: string): string;
|
|
1638
|
+
private loadMore;
|
|
1639
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopifyFilePickerComponent, never>;
|
|
1640
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ShopifyFilePickerComponent, "lib-shopify-file-picker", never, { "mediaType": { "alias": "mediaType"; "required": true; "isSignal": true; }; "currentValue": { "alias": "currentValue"; "required": false; "isSignal": true; }; }, { "fileSelected": "fileSelected"; "closed": "closed"; }, never, never, true, never>;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
/**
|
|
1644
|
+
* Page manager component for listing, creating, and managing pages
|
|
1645
|
+
*/
|
|
1646
|
+
declare class PageManagerComponent implements OnInit {
|
|
1647
|
+
private readonly facade;
|
|
1648
|
+
private readonly navigation;
|
|
1649
|
+
readonly pages: _angular_core.WritableSignal<PageSummary[]>;
|
|
1650
|
+
readonly isLoading: _angular_core.WritableSignal<boolean>;
|
|
1651
|
+
readonly error: _angular_core.WritableSignal<string | null>;
|
|
1652
|
+
readonly showCreateDialog: _angular_core.WritableSignal<boolean>;
|
|
1653
|
+
readonly newPageTitle: _angular_core.WritableSignal<string>;
|
|
1654
|
+
readonly newPageSlug: _angular_core.WritableSignal<string>;
|
|
1655
|
+
readonly isCreating: _angular_core.WritableSignal<boolean>;
|
|
1656
|
+
readonly createError: _angular_core.WritableSignal<string | null>;
|
|
1657
|
+
readonly pageToDelete: _angular_core.WritableSignal<PageSummary | null>;
|
|
1658
|
+
readonly isDeleting: _angular_core.WritableSignal<boolean>;
|
|
1659
|
+
ngOnInit(): void;
|
|
1660
|
+
loadPages(): void;
|
|
1661
|
+
openCreateDialog(): void;
|
|
1662
|
+
closeCreateDialog(): void;
|
|
1663
|
+
onTitleInput(event: Event): void;
|
|
1664
|
+
onSlugInput(event: Event): void;
|
|
1665
|
+
createPage(event: Event): void;
|
|
1666
|
+
editPage(pageId: string): void;
|
|
1667
|
+
duplicatePage(pageId: string, event: Event): void;
|
|
1668
|
+
confirmDelete(page: PageSummary, event: Event): void;
|
|
1669
|
+
cancelDelete(): void;
|
|
1670
|
+
deletePage(): void;
|
|
1671
|
+
formatDate(dateString: string): string;
|
|
1672
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PageManagerComponent, never>;
|
|
1673
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<PageManagerComponent, "lib-page-manager", never, {}, {}, never, never, true, never>;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
/**
|
|
1677
|
+
* Token para inyectar el dominio de la tienda.
|
|
1678
|
+
* Debe ser configurado por la aplicación que instala el editor.
|
|
1679
|
+
*
|
|
1680
|
+
* Ejemplo de uso:
|
|
1681
|
+
* ```typescript
|
|
1682
|
+
* providers: [
|
|
1683
|
+
* { provide: STORE_DOMAIN, useValue: 'nike.com' }
|
|
1684
|
+
* ]
|
|
1685
|
+
* ```
|
|
1686
|
+
*
|
|
1687
|
+
* Si no se provee, el servicio intentará detectar el dominio desde window.location.hostname
|
|
1688
|
+
*/
|
|
1689
|
+
declare const STORE_DOMAIN: InjectionToken<string>;
|
|
1690
|
+
interface Shop {
|
|
1691
|
+
id: string;
|
|
1692
|
+
name: string;
|
|
1693
|
+
shopify_domain: string;
|
|
1694
|
+
}
|
|
1695
|
+
interface ShopUser {
|
|
1696
|
+
email: string;
|
|
1697
|
+
role: 'owner' | 'admin' | 'reader';
|
|
1698
|
+
}
|
|
1699
|
+
interface ShopLicense {
|
|
1700
|
+
tier: 'starter' | 'growth' | 'enterprise';
|
|
1701
|
+
expires_at: string | null;
|
|
1702
|
+
active: boolean;
|
|
1703
|
+
}
|
|
1704
|
+
interface ShopAuthData {
|
|
1705
|
+
shop: Shop | null;
|
|
1706
|
+
user: ShopUser | null;
|
|
1707
|
+
license: ShopLicense | null;
|
|
1708
|
+
}
|
|
1709
|
+
interface ShopAuthError {
|
|
1710
|
+
code: string;
|
|
1711
|
+
message: string;
|
|
1712
|
+
}
|
|
1713
|
+
declare class ShopAuthService {
|
|
1714
|
+
private http;
|
|
1715
|
+
private config;
|
|
1716
|
+
private authService;
|
|
1717
|
+
private storeDomainConfig;
|
|
1718
|
+
private _shop;
|
|
1719
|
+
private _user;
|
|
1720
|
+
private _license;
|
|
1721
|
+
private _loading;
|
|
1722
|
+
private _error;
|
|
1723
|
+
private _initialized;
|
|
1724
|
+
readonly shop: _angular_core.Signal<Shop | null>;
|
|
1725
|
+
readonly user: _angular_core.Signal<ShopUser | null>;
|
|
1726
|
+
readonly license: _angular_core.Signal<ShopLicense | null>;
|
|
1727
|
+
readonly loading: _angular_core.Signal<boolean>;
|
|
1728
|
+
readonly error: _angular_core.Signal<ShopAuthError | null>;
|
|
1729
|
+
readonly initialized: _angular_core.Signal<boolean>;
|
|
1730
|
+
readonly shopId: _angular_core.Signal<string | null>;
|
|
1731
|
+
readonly shopName: _angular_core.Signal<string | null>;
|
|
1732
|
+
readonly shopifyDomain: _angular_core.Signal<string | null>;
|
|
1733
|
+
readonly userEmail: _angular_core.Signal<string | null>;
|
|
1734
|
+
readonly userRole: _angular_core.Signal<"owner" | "admin" | "reader" | null>;
|
|
1735
|
+
readonly isOwner: _angular_core.Signal<boolean>;
|
|
1736
|
+
readonly isAdmin: _angular_core.Signal<boolean>;
|
|
1737
|
+
readonly canEdit: _angular_core.Signal<boolean>;
|
|
1738
|
+
readonly licenseTier: _angular_core.Signal<"starter" | "growth" | "enterprise" | null>;
|
|
1739
|
+
readonly licenseActive: _angular_core.Signal<boolean>;
|
|
1740
|
+
readonly licenseExpiresAt: _angular_core.Signal<string | null>;
|
|
1741
|
+
readonly hasAccess: _angular_core.Signal<boolean>;
|
|
1742
|
+
readonly daysRemaining: _angular_core.Signal<number | null>;
|
|
1743
|
+
readonly isLicenseExpiringSoon: _angular_core.Signal<boolean>;
|
|
1744
|
+
/**
|
|
1745
|
+
* Obtiene el dominio actual.
|
|
1746
|
+
* Prioridad:
|
|
1747
|
+
* 1. STORE_DOMAIN token (inyectado)
|
|
1748
|
+
* 2. Query param ?shop= (solo en localhost)
|
|
1749
|
+
* 3. window.location.hostname
|
|
1750
|
+
*/
|
|
1751
|
+
getCurrentDomain(): string;
|
|
1752
|
+
/**
|
|
1753
|
+
* Autentica al usuario para el dominio actual.
|
|
1754
|
+
* Esta es la función principal que debe llamarse al cargar la app.
|
|
1755
|
+
*/
|
|
1756
|
+
authenticate(): Promise<ShopAuthData>;
|
|
1757
|
+
/**
|
|
1758
|
+
* Limpia el estado (para logout)
|
|
1759
|
+
*/
|
|
1760
|
+
clear(): void;
|
|
1761
|
+
/**
|
|
1762
|
+
* Refresca la autenticación
|
|
1763
|
+
*/
|
|
1764
|
+
refresh(): Promise<ShopAuthData>;
|
|
1765
|
+
/**
|
|
1766
|
+
* Verifica si el error actual indica que el usuario no tiene acceso
|
|
1767
|
+
*/
|
|
1768
|
+
isNoAccessError(): boolean;
|
|
1769
|
+
/**
|
|
1770
|
+
* Verifica si el error actual indica que la licencia expiró
|
|
1771
|
+
*/
|
|
1772
|
+
isLicenseExpiredError(): boolean;
|
|
1773
|
+
/**
|
|
1774
|
+
* Verifica si el usuario está inactivo
|
|
1775
|
+
*/
|
|
1776
|
+
isUserInactiveError(): boolean;
|
|
1777
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopAuthService, never>;
|
|
1778
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShopAuthService>;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
declare class LicenseGuardComponent {
|
|
1782
|
+
shopAuthService: ShopAuthService;
|
|
1783
|
+
showExpirationWarning: _angular_core.InputSignal<boolean>;
|
|
1784
|
+
subscribe: _angular_core.OutputEmitterRef<void>;
|
|
1785
|
+
renew: _angular_core.OutputEmitterRef<void>;
|
|
1786
|
+
reauth: _angular_core.OutputEmitterRef<void>;
|
|
1787
|
+
retry: _angular_core.OutputEmitterRef<void>;
|
|
1788
|
+
onSubscribe(): void;
|
|
1789
|
+
onRenew(): void;
|
|
1790
|
+
onReauth(): void;
|
|
1791
|
+
onRetry(): void;
|
|
1792
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LicenseGuardComponent, never>;
|
|
1793
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LicenseGuardComponent, "lib-license-guard", never, { "showExpirationWarning": { "alias": "showExpirationWarning"; "required": false; "isSignal": true; }; }, { "subscribe": "subscribe"; "renew": "renew"; "reauth": "reauth"; "retry": "retry"; }, never, ["*"], true, never>;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
declare class LoginComponent {
|
|
1797
|
+
private authService;
|
|
1798
|
+
private router;
|
|
1799
|
+
loginSuccess: _angular_core.OutputEmitterRef<void>;
|
|
1800
|
+
email: _angular_core.WritableSignal<string>;
|
|
1801
|
+
password: _angular_core.WritableSignal<string>;
|
|
1802
|
+
error: _angular_core.WritableSignal<string | null>;
|
|
1803
|
+
loading: _angular_core.WritableSignal<boolean>;
|
|
1804
|
+
isSignUp: _angular_core.WritableSignal<boolean>;
|
|
1805
|
+
showPassword: _angular_core.WritableSignal<boolean>;
|
|
1806
|
+
toggleMode(): void;
|
|
1807
|
+
togglePassword(): void;
|
|
1808
|
+
onSubmit(): Promise<void>;
|
|
1809
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LoginComponent, never>;
|
|
1810
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LoginComponent, "lib-login", never, {}, { "loginSuccess": "loginSuccess"; }, never, never, true, never>;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
type ViewState = 'loading' | 'no-store' | 'license-expired';
|
|
1814
|
+
declare class ActivateLicenseComponent implements OnInit {
|
|
1815
|
+
shopAuthService: ShopAuthService;
|
|
1816
|
+
viewState: _angular_core.Signal<ViewState>;
|
|
1817
|
+
ngOnInit(): void;
|
|
1818
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ActivateLicenseComponent, never>;
|
|
1819
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ActivateLicenseComponent, "lib-activate-license", never, {}, {}, never, never, true, never>;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
interface SupabaseConfig {
|
|
1823
|
+
supabaseUrl: string;
|
|
1824
|
+
supabaseAnonKey: string;
|
|
1825
|
+
}
|
|
1826
|
+
declare const SUPABASE_CONFIG: InjectionToken<SupabaseConfig>;
|
|
1827
|
+
declare class SupabaseAuthService implements OnDestroy {
|
|
1828
|
+
private config;
|
|
1829
|
+
private supabase;
|
|
1830
|
+
private supabasePromise;
|
|
1831
|
+
private authSubscription;
|
|
1832
|
+
private _session;
|
|
1833
|
+
private _user;
|
|
1834
|
+
private _loading;
|
|
1835
|
+
private _error;
|
|
1836
|
+
private _initialized;
|
|
1837
|
+
readonly session: _angular_core.Signal<Session | null>;
|
|
1838
|
+
readonly user: _angular_core.Signal<User | null>;
|
|
1839
|
+
readonly loading: _angular_core.Signal<boolean>;
|
|
1840
|
+
readonly error: _angular_core.Signal<string | null>;
|
|
1841
|
+
readonly initialized: _angular_core.Signal<boolean>;
|
|
1842
|
+
readonly isAuthenticated: _angular_core.Signal<boolean>;
|
|
1843
|
+
readonly accessToken: _angular_core.Signal<string | null>;
|
|
1844
|
+
readonly userEmail: _angular_core.Signal<string | null>;
|
|
1845
|
+
private getSupabaseClient;
|
|
1846
|
+
private initializeClient;
|
|
1847
|
+
ensureInitialized(): Promise<void>;
|
|
1848
|
+
signInWithPassword(email: string, password: string): Promise<{
|
|
1849
|
+
success: boolean;
|
|
1850
|
+
error?: string;
|
|
1851
|
+
}>;
|
|
1852
|
+
signUp(email: string, password: string): Promise<{
|
|
1853
|
+
success: boolean;
|
|
1854
|
+
error?: string;
|
|
1855
|
+
}>;
|
|
1856
|
+
signOut(): Promise<void>;
|
|
1857
|
+
resetPassword(email: string): Promise<{
|
|
1858
|
+
success: boolean;
|
|
1859
|
+
error?: string;
|
|
1860
|
+
}>;
|
|
1861
|
+
getClient(): Promise<SupabaseClient | null>;
|
|
1862
|
+
ngOnDestroy(): void;
|
|
1863
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SupabaseAuthService, never>;
|
|
1864
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<SupabaseAuthService>;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
declare class AppShellComponent {
|
|
1868
|
+
authService: SupabaseAuthService;
|
|
1869
|
+
shopAuthService: ShopAuthService;
|
|
1870
|
+
loggedOut: _angular_core.OutputEmitterRef<void>;
|
|
1871
|
+
logout(): Promise<void>;
|
|
1872
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AppShellComponent, never>;
|
|
1873
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AppShellComponent, "lib-app-shell", never, {}, { "loggedOut": "loggedOut"; }, never, ["*"], true, never>;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
declare class NoAccessComponent {
|
|
1877
|
+
backToLogin: _angular_core.OutputEmitterRef<void>;
|
|
1878
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NoAccessComponent, never>;
|
|
1879
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NoAccessComponent, "ke-no-access", never, {}, { "backToLogin": "backToLogin"; }, never, never, true, never>;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
declare class LicenseExpiredComponent {
|
|
1883
|
+
backToLogin: _angular_core.OutputEmitterRef<void>;
|
|
1884
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LicenseExpiredComponent, never>;
|
|
1885
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LicenseExpiredComponent, "ke-license-expired", never, {}, { "backToLogin": "backToLogin"; }, never, never, true, never>;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
/**
|
|
1889
|
+
* Injection token to enable in-memory page storage (for development)
|
|
1890
|
+
* When false (default), uses Shopify metafields via GraphQL API
|
|
1891
|
+
*/
|
|
1892
|
+
declare const USE_IN_MEMORY_PAGES: InjectionToken<boolean>;
|
|
1893
|
+
/**
|
|
1894
|
+
* Injection token for page environment (metafield key prefix).
|
|
1895
|
+
* Default is 'production'.
|
|
1896
|
+
*/
|
|
1897
|
+
declare const PAGE_ENVIRONMENT: InjectionToken<string>;
|
|
1898
|
+
declare class PageService {
|
|
1899
|
+
private readonly useInMemory;
|
|
1900
|
+
private readonly pageEnvironment;
|
|
1901
|
+
private readonly memoryRepo;
|
|
1902
|
+
private readonly shopifyRepo;
|
|
1903
|
+
private resolveEnvironment;
|
|
1904
|
+
/**
|
|
1905
|
+
* Get all pages (summaries only for listing)
|
|
1906
|
+
*/
|
|
1907
|
+
getPages(environment?: string): Observable<PageSummary[]>;
|
|
1908
|
+
/**
|
|
1909
|
+
* Get a single page by ID (full content)
|
|
1910
|
+
*/
|
|
1911
|
+
getPage(id: string, environment?: string): Observable<Page>;
|
|
1912
|
+
/**
|
|
1913
|
+
* Get a published page by slug (for public rendering)
|
|
1914
|
+
*/
|
|
1915
|
+
getPublishedPageBySlug(slug: string, environment?: string): Observable<Page>;
|
|
1916
|
+
/**
|
|
1917
|
+
* Create a new page
|
|
1918
|
+
*/
|
|
1919
|
+
createPage(request: CreatePageRequest, environment?: string): Observable<Page>;
|
|
1920
|
+
/**
|
|
1921
|
+
* Update an existing page
|
|
1922
|
+
*/
|
|
1923
|
+
updatePage(id: string, request: UpdatePageRequest, environment?: string): Observable<Page>;
|
|
1924
|
+
/**
|
|
1925
|
+
* Delete a page
|
|
1926
|
+
*/
|
|
1927
|
+
deletePage(id: string, environment?: string): Observable<void>;
|
|
1928
|
+
/**
|
|
1929
|
+
* Publish a page (changes status to 'published')
|
|
1930
|
+
*/
|
|
1931
|
+
publishPage(id: string, request: PublishPageRequest, environment?: string): Observable<Page>;
|
|
1932
|
+
/**
|
|
1933
|
+
* Unpublish a page (changes status to 'draft')
|
|
1934
|
+
*/
|
|
1935
|
+
unpublishPage(id: string, request: PublishPageRequest, environment?: string): Observable<Page>;
|
|
1936
|
+
/**
|
|
1937
|
+
* Duplicate an existing page
|
|
1938
|
+
*/
|
|
1939
|
+
duplicatePage(id: string, environment?: string): Observable<Page>;
|
|
1940
|
+
/**
|
|
1941
|
+
* Delete all pages for a given environment
|
|
1942
|
+
*/
|
|
1943
|
+
deletePagesByEnvironment(environment?: string): Observable<void>;
|
|
1944
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PageService, never>;
|
|
1945
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<PageService>;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
interface ShopifyAppConfig {
|
|
1949
|
+
appUrl: string;
|
|
1950
|
+
}
|
|
1951
|
+
interface ShopifyTokenResponse {
|
|
1952
|
+
accessToken: string;
|
|
1953
|
+
shopifyDomain: string;
|
|
1954
|
+
}
|
|
1955
|
+
type TokenErrorCode = 'NOT_AUTHENTICATED' | 'NO_ACTIVE_STORE' | 'TOKEN_FETCH_FAILED' | 'SESSION_EXPIRED' | 'NO_STORE_ACCESS' | 'NETWORK_ERROR' | 'UNKNOWN_ERROR';
|
|
1956
|
+
interface TokenError {
|
|
1957
|
+
code: TokenErrorCode;
|
|
1958
|
+
message: string;
|
|
1959
|
+
status?: number;
|
|
1960
|
+
}
|
|
1961
|
+
declare const SHOPIFY_APP_CONFIG: InjectionToken<ShopifyAppConfig>;
|
|
1962
|
+
declare class ShopifyTokenService {
|
|
1963
|
+
private readonly http;
|
|
1964
|
+
private readonly config;
|
|
1965
|
+
private readonly authService;
|
|
1966
|
+
private readonly shopAuthService;
|
|
1967
|
+
private readonly CACHE_TTL_MS;
|
|
1968
|
+
private readonly tokenCache;
|
|
1969
|
+
private readonly _currentToken;
|
|
1970
|
+
private readonly _currentDomain;
|
|
1971
|
+
private readonly _loading;
|
|
1972
|
+
private readonly _error;
|
|
1973
|
+
private pendingRequest;
|
|
1974
|
+
readonly currentToken: _angular_core.Signal<string | null>;
|
|
1975
|
+
readonly currentDomain: _angular_core.Signal<string | null>;
|
|
1976
|
+
readonly loading: _angular_core.Signal<boolean>;
|
|
1977
|
+
readonly error: _angular_core.Signal<TokenError | null>;
|
|
1978
|
+
readonly hasToken: _angular_core.Signal<boolean>;
|
|
1979
|
+
readonly isReady: _angular_core.Signal<boolean>;
|
|
1980
|
+
getToken(): Observable<ShopifyTokenResponse>;
|
|
1981
|
+
getTokenForDomain(shopifyDomain: string): Observable<ShopifyTokenResponse>;
|
|
1982
|
+
refreshToken(): Observable<ShopifyTokenResponse>;
|
|
1983
|
+
invalidateCache(shopifyDomain?: string): void;
|
|
1984
|
+
clear(): void;
|
|
1985
|
+
private fetchToken;
|
|
1986
|
+
private getCachedToken;
|
|
1987
|
+
private setCachedToken;
|
|
1988
|
+
private handleHttpError;
|
|
1989
|
+
private createError;
|
|
1990
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopifyTokenService, never>;
|
|
1991
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShopifyTokenService>;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
type GraphQLErrorCode = 'GRAPHQL_ERROR' | 'EMPTY_RESPONSE' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'RATE_LIMIT' | 'SERVER_ERROR' | 'NETWORK_ERROR' | 'HTTP_ERROR' | 'TOKEN_ERROR' | 'UNKNOWN_ERROR';
|
|
1995
|
+
interface GraphQLError {
|
|
1996
|
+
code: GraphQLErrorCode;
|
|
1997
|
+
message: string;
|
|
1998
|
+
status?: number;
|
|
1999
|
+
errors?: Array<{
|
|
2000
|
+
message: string;
|
|
2001
|
+
}>;
|
|
2002
|
+
original?: unknown;
|
|
2003
|
+
}
|
|
2004
|
+
declare class ShopifyGraphQLClient {
|
|
2005
|
+
private readonly http;
|
|
2006
|
+
private readonly authService;
|
|
2007
|
+
private readonly shopAuthService;
|
|
2008
|
+
private readonly config;
|
|
2009
|
+
query<T>(query: string, variables?: Record<string, unknown>): Observable<T>;
|
|
2010
|
+
mutate<T>(mutation: string, variables?: Record<string, unknown>): Observable<T>;
|
|
2011
|
+
private executeOperation;
|
|
2012
|
+
private handleResponse;
|
|
2013
|
+
private handleHttpError;
|
|
2014
|
+
private createError;
|
|
2015
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopifyGraphQLClient, never>;
|
|
2016
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShopifyGraphQLClient>;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
2019
|
+
declare const NAMESPACE = "kustomizer";
|
|
2020
|
+
declare const INDEX_KEY = "pages_index";
|
|
2021
|
+
declare const MAX_METAFIELD_SIZE: number;
|
|
2022
|
+
declare const GET_SHOP_METAFIELD_QUERY = "\n query GetShopMetafield($namespace: String!, $key: String!) {\n shop {\n id\n metafield(namespace: $namespace, key: $key) {\n id\n value\n createdAt\n updatedAt\n }\n }\n }\n";
|
|
2023
|
+
declare const SET_METAFIELD_MUTATION = "\n mutation SetMetafield($metafields: [MetafieldsSetInput!]!) {\n metafieldsSet(metafields: $metafields) {\n metafields {\n id\n namespace\n key\n value\n }\n userErrors {\n field\n message\n }\n }\n }\n";
|
|
2024
|
+
declare const DELETE_METAFIELDS_MUTATION = "\n mutation DeleteMetafields($metafields: [MetafieldIdentifierInput!]!) {\n metafieldsDelete(metafields: $metafields) {\n deletedMetafields {\n key\n namespace\n }\n userErrors {\n field\n message\n }\n }\n }\n";
|
|
2025
|
+
declare const GET_SHOP_ID_QUERY = "\n query GetShopId {\n shop {\n id\n }\n }\n";
|
|
2026
|
+
declare class ShopifyMetafieldRepository {
|
|
2027
|
+
private readonly client;
|
|
2028
|
+
private resolveEnvironment;
|
|
2029
|
+
private buildIndexKey;
|
|
2030
|
+
private buildPageKey;
|
|
2031
|
+
getMetafield(namespace: string, key: string): Observable<Metafield | null>;
|
|
2032
|
+
setMetafield(namespace: string, key: string, value: any, ownerId: string): Observable<Metafield>;
|
|
2033
|
+
deleteMetafield(namespace: string, key: string): Observable<void>;
|
|
2034
|
+
getShopId(): Observable<string>;
|
|
2035
|
+
getPageIndex(environment?: string): Observable<PagesIndex>;
|
|
2036
|
+
updatePageIndex(index: PagesIndex, environment?: string): Observable<PagesIndex>;
|
|
2037
|
+
getPageMetafield(pageId: string, environment?: string): Observable<Page | null>;
|
|
2038
|
+
setPageMetafield(pageId: string, page: Page, environment?: string): Observable<Page>;
|
|
2039
|
+
deletePageMetafield(pageId: string, environment?: string): Observable<void>;
|
|
2040
|
+
resetPageIndex(environment?: string): Observable<PagesIndex>;
|
|
2041
|
+
validateSize(data: any): {
|
|
2042
|
+
valid: boolean;
|
|
2043
|
+
size: number;
|
|
2044
|
+
percentUsed: number;
|
|
2045
|
+
};
|
|
2046
|
+
private getDefaultIndex;
|
|
2047
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopifyMetafieldRepository, never>;
|
|
2048
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShopifyMetafieldRepository>;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
declare class PageShopifyRepository {
|
|
2052
|
+
private readonly metafieldRepo;
|
|
2053
|
+
private resolveEnvironment;
|
|
2054
|
+
getPages(environment?: string): Observable<PageSummary[]>;
|
|
2055
|
+
getPage(id: string, environment?: string): Observable<Page>;
|
|
2056
|
+
getPublishedPageBySlug(slug: string, environment?: string): Observable<Page>;
|
|
2057
|
+
createPage(request: CreatePageRequest, environment?: string): Observable<Page>;
|
|
2058
|
+
updatePage(id: string, request: UpdatePageRequest, environment?: string): Observable<Page>;
|
|
2059
|
+
deletePage(id: string, environment?: string): Observable<void>;
|
|
2060
|
+
publishPage(id: string, request: PublishPageRequest, environment?: string): Observable<Page>;
|
|
2061
|
+
unpublishPage(id: string, request: PublishPageRequest, environment?: string): Observable<Page>;
|
|
2062
|
+
duplicatePage(id: string, environment?: string): Observable<Page>;
|
|
2063
|
+
deletePagesByEnvironment(environment?: string): Observable<void>;
|
|
2064
|
+
private validateUniqueSlug;
|
|
2065
|
+
private generateUniqueSlug;
|
|
2066
|
+
private addPageToIndex;
|
|
2067
|
+
private updatePageInIndex;
|
|
2068
|
+
private removePageFromIndex;
|
|
2069
|
+
private mapIndexEntryToSummary;
|
|
2070
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PageShopifyRepository, never>;
|
|
2071
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<PageShopifyRepository>;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
interface TeamMember {
|
|
2075
|
+
email: string;
|
|
2076
|
+
role: 'owner' | 'admin' | 'reader';
|
|
2077
|
+
status: 'active' | 'inactive' | 'suspended';
|
|
2078
|
+
invited_by: string | null;
|
|
2079
|
+
joined_at: string;
|
|
2080
|
+
is_current_user: boolean;
|
|
2081
|
+
}
|
|
2082
|
+
interface PendingInvitation {
|
|
2083
|
+
id: string;
|
|
2084
|
+
email: string;
|
|
2085
|
+
role: 'admin' | 'reader';
|
|
2086
|
+
invited_by: string;
|
|
2087
|
+
created_at: string;
|
|
2088
|
+
expires_at: string;
|
|
2089
|
+
is_expired: boolean;
|
|
2090
|
+
}
|
|
2091
|
+
interface CurrentUser {
|
|
2092
|
+
email: string;
|
|
2093
|
+
role: string;
|
|
2094
|
+
can_invite: boolean;
|
|
2095
|
+
can_remove_members: boolean;
|
|
2096
|
+
}
|
|
2097
|
+
interface TeamData {
|
|
2098
|
+
shop: {
|
|
2099
|
+
id: string;
|
|
2100
|
+
name: string;
|
|
2101
|
+
shopify_domain: string;
|
|
2102
|
+
allowed_domains: string[];
|
|
2103
|
+
};
|
|
2104
|
+
members: TeamMember[];
|
|
2105
|
+
invitations: PendingInvitation[];
|
|
2106
|
+
current_user: CurrentUser;
|
|
2107
|
+
summary: {
|
|
2108
|
+
total_members: number;
|
|
2109
|
+
pending_invitations: number;
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
interface InviteResult {
|
|
2113
|
+
invitation_id: string;
|
|
2114
|
+
token: string;
|
|
2115
|
+
expires_at: string;
|
|
2116
|
+
email: string;
|
|
2117
|
+
role: string;
|
|
2118
|
+
}
|
|
2119
|
+
interface AcceptInvitationResult {
|
|
2120
|
+
success: boolean;
|
|
2121
|
+
shop: {
|
|
2122
|
+
id: string;
|
|
2123
|
+
name: string;
|
|
2124
|
+
shopify_domain: string;
|
|
2125
|
+
};
|
|
2126
|
+
role: string;
|
|
2127
|
+
message: string;
|
|
2128
|
+
}
|
|
2129
|
+
declare class ShopTeamService {
|
|
2130
|
+
private http;
|
|
2131
|
+
private config;
|
|
2132
|
+
private authService;
|
|
2133
|
+
private shopAuthService;
|
|
2134
|
+
private _team;
|
|
2135
|
+
private _loading;
|
|
2136
|
+
private _error;
|
|
2137
|
+
readonly team: _angular_core.Signal<TeamData | null>;
|
|
2138
|
+
readonly loading: _angular_core.Signal<boolean>;
|
|
2139
|
+
readonly error: _angular_core.Signal<string | null>;
|
|
2140
|
+
readonly members: _angular_core.Signal<TeamMember[]>;
|
|
2141
|
+
readonly invitations: _angular_core.Signal<PendingInvitation[]>;
|
|
2142
|
+
readonly currentUser: _angular_core.Signal<CurrentUser | null>;
|
|
2143
|
+
readonly activeMembers: _angular_core.Signal<TeamMember[]>;
|
|
2144
|
+
readonly pendingInvitations: _angular_core.Signal<PendingInvitation[]>;
|
|
2145
|
+
readonly canInvite: _angular_core.Signal<boolean>;
|
|
2146
|
+
/**
|
|
2147
|
+
* Carga el equipo de la shop actual
|
|
2148
|
+
*/
|
|
2149
|
+
loadTeam(): Promise<TeamData | null>;
|
|
2150
|
+
/**
|
|
2151
|
+
* Invita a un usuario a la shop
|
|
2152
|
+
*/
|
|
2153
|
+
inviteUser(email: string, role: 'admin' | 'reader', message?: string): Promise<InviteResult | null>;
|
|
2154
|
+
/**
|
|
2155
|
+
* Acepta una invitación (usado cuando un usuario hace click en el link de invitación)
|
|
2156
|
+
*/
|
|
2157
|
+
acceptInvitation(invitationToken: string): Promise<AcceptInvitationResult | null>;
|
|
2158
|
+
/**
|
|
2159
|
+
* Genera el URL de invitación (para copiar/compartir)
|
|
2160
|
+
*/
|
|
2161
|
+
getInvitationUrl(token: string, baseUrl?: string): string;
|
|
2162
|
+
/**
|
|
2163
|
+
* Limpia el estado
|
|
2164
|
+
*/
|
|
2165
|
+
clear(): void;
|
|
2166
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShopTeamService, never>;
|
|
2167
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ShopTeamService>;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
declare const authGuard: CanActivateFn;
|
|
2171
|
+
declare const noAuthGuard: CanActivateFn;
|
|
2172
|
+
|
|
2173
|
+
declare const licenseGuard: CanActivateFn;
|
|
2174
|
+
declare const noLicenseGuard: CanActivateFn;
|
|
2175
|
+
|
|
2176
|
+
/**
|
|
2177
|
+
* Guard que verifica:
|
|
2178
|
+
* 1. Usuario autenticado
|
|
2179
|
+
* 2. Usuario tiene acceso a la shop del dominio actual
|
|
2180
|
+
* 3. Licencia activa
|
|
2181
|
+
*
|
|
2182
|
+
* Redirige a:
|
|
2183
|
+
* - /login si no está autenticado
|
|
2184
|
+
* - /no-access si no tiene acceso a la shop
|
|
2185
|
+
* - /license-expired si la licencia expiró
|
|
2186
|
+
*/
|
|
2187
|
+
declare const shopAuthGuard: CanActivateFn;
|
|
2188
|
+
/**
|
|
2189
|
+
* Guard que solo permite acceso si el usuario NO tiene acceso a una shop.
|
|
2190
|
+
* Útil para páginas como /login que no deberían ser accesibles si ya tienes acceso.
|
|
2191
|
+
*/
|
|
2192
|
+
declare const noShopAuthGuard: CanActivateFn;
|
|
2193
|
+
/**
|
|
2194
|
+
* Guard que verifica que el usuario tenga rol de admin o owner.
|
|
2195
|
+
* Requiere que shopAuthGuard se haya ejecutado primero.
|
|
2196
|
+
*/
|
|
2197
|
+
declare const shopAdminGuard: CanActivateFn;
|
|
2198
|
+
/**
|
|
2199
|
+
* Guard que verifica que el usuario pueda editar (owner o admin).
|
|
2200
|
+
* Los readers solo pueden ver, no editar.
|
|
2201
|
+
*/
|
|
2202
|
+
declare const shopEditorGuard: CanActivateFn;
|
|
2203
|
+
|
|
2204
|
+
declare class DragDropService {
|
|
2205
|
+
private readonly store;
|
|
2206
|
+
private readonly registry;
|
|
2207
|
+
private readonly sections;
|
|
2208
|
+
readonly dragItem: _angular_core.WritableSignal<DragItem | null>;
|
|
2209
|
+
readonly dropTarget: _angular_core.WritableSignal<DropTarget | null>;
|
|
2210
|
+
readonly isDragging: _angular_core.Signal<boolean>;
|
|
2211
|
+
startDrag(item: DragItem, event: DragEvent): void;
|
|
2212
|
+
endDrag(): void;
|
|
2213
|
+
updateDropTarget(target: DropTarget | null): void;
|
|
2214
|
+
computeDropZone(event: DragEvent, element: HTMLElement, canDropInside: boolean): DropZone;
|
|
2215
|
+
validateDrop(item: DragItem, target: DropTarget): boolean;
|
|
2216
|
+
executeDrop(): void;
|
|
2217
|
+
private executeSectionDrop;
|
|
2218
|
+
private executeBlockDrop;
|
|
2219
|
+
private isDropOnSelf;
|
|
2220
|
+
private wouldCreateCircular;
|
|
2221
|
+
private isTypeAllowedInSlot;
|
|
2222
|
+
private findElementInTree;
|
|
2223
|
+
private isDescendant;
|
|
2224
|
+
private pathsEqual;
|
|
2225
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DragDropService, never>;
|
|
2226
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DragDropService>;
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
declare class VisualEditor {
|
|
2230
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<VisualEditor, never>;
|
|
2231
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<VisualEditor, "lib-visual-editor", never, {}, {}, never, never, true, never>;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
export { ActivateLicenseComponent, AppShellComponent, BlockTreeItemComponent, ComponentRegistryService, DEFAULT_ROUTER_NAVIGATION_CONFIG, DEFAULT_VISUAL_EDITOR_CONFIG, DELETE_METAFIELDS_MUTATION, DefaultRouterNavigationService, DragDropService, DynamicRendererComponent, EDITOR_COMPONENT_DEFINITIONS, FILES_QUERY, GET_SHOP_ID_QUERY, GET_SHOP_METAFIELD_QUERY, INDEX_KEY, InputPageLoadingStrategy, LicenseExpiredComponent, LicenseGuardComponent, LoginComponent, MAX_METAFIELD_SIZE, NAMESPACE, NoAccessComponent, PAGE_ENVIRONMENT, PageLoadingStrategy, PageManagerComponent, PageService, PageShopifyRepository, ROUTER_NAVIGATION_CONFIG, RoutePageLoadingStrategy, SET_METAFIELD_MUTATION, SHOPIFY_API_VERSION, SHOPIFY_APP_CONFIG, SHOPIFY_CONFIG, STORE_DOMAIN, SUPABASE_CONFIG, ShopAuthService, ShopTeamService, ShopifyFilePickerComponent, ShopifyFilesService, ShopifyGraphQLClient, ShopifyMetafieldRepository, ShopifyTokenService, SlotRendererComponent, SupabaseAuthService, USE_IN_MEMORY_PAGES, VISUAL_EDITOR_CONFIG, VISUAL_EDITOR_FEATURE_KEY, VisualEditor, VisualEditorActions, VisualEditorComponent, VisualEditorFacade, VisualEditorNavigation, authGuard, initialVisualEditorState, licenseGuard, noAuthGuard, noLicenseGuard, noShopAuthGuard, provideEditorComponents, provideVisualEditor, provideVisualEditorStore, selectBlocksForSection, selectBlocksForSlot, selectCanRedo, selectCanUndo, selectCurrentPage, selectCurrentPageId, selectCurrentPageSlug, selectCurrentPageStatus, selectCurrentPageTitle, selectCurrentPageVersion, selectDraggedElementId, selectElementById, selectHistory, selectHistoryIndex, selectHistoryLength, selectIsDirty, selectIsDragging, selectIsPageLoaded, selectLastAction, selectSectionById, selectSections, selectSelectedBlock, selectSelectedBlockSlotName, selectSelectedElement, selectSelectedElementId, selectSelectedElementType, selectSelectedSection, selectSelectedSectionId, selectSelectedSectionType, selectVisualEditorState, shopAdminGuard, shopAuthGuard, shopEditorGuard, visualEditorReducer };
|
|
2235
|
+
export type { AcceptInvitationResult, BlockPickerTarget, BlockTreeContext, ComponentCategory, ComponentDefinition, ComponentPreset, ConfirmDialogOptions, CreatePageRequest, CurrentUser, DragItem, DragItemKind, DropTarget, DropZone, EditorElement, EditorSection, GraphQLError, GraphQLErrorCode, HistoryEntry, InviteResult, Metafield, Page, PageContext, PageIndexEntry, PageStatus, PageSummary, PagesIndex, PendingInvitation, PresetBlockConfig, PropCondition, PropSchema, PropSchemaMap, PropType, PropValidation, PublishPageRequest, ResolvedPreset, RouterNavigationConfig, SelectOption, Shop, ShopAuthData, ShopAuthError, ShopLicense, ShopUser, ShopifyAppConfig, ShopifyConfig, ShopifyFile, ShopifyFilesPage, ShopifyTokenResponse, SlotConstraints, SlotDefinition, SupabaseConfig, TeamData, TeamMember, TokenError, TokenErrorCode, UpdatePageRequest, VisualEditorConfig, VisualEditorNavigationTarget, VisualEditorState };
|