@praxisui/expansion 1.0.0-beta.7 → 2.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -6
- package/fesm2022/praxisui-expansion.mjs +1151 -111
- package/fesm2022/praxisui-expansion.mjs.map +1 -1
- package/index.d.ts +133 -10
- package/package.json +9 -9
|
@@ -1,23 +1,196 @@
|
|
|
1
1
|
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { EventEmitter, inject, DestroyRef, ViewChildren, ViewChild, Output, Input, ChangeDetectionStrategy, Component, ENVIRONMENT_INITIALIZER } from '@angular/core';
|
|
4
|
+
import { EventEmitter, inject, ChangeDetectorRef, DestroyRef, ViewChildren, ViewChild, Output, Input, ChangeDetectionStrategy, Component, Inject, ENVIRONMENT_INITIALIZER } from '@angular/core';
|
|
5
|
+
import { ActivatedRoute } from '@angular/router';
|
|
5
6
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
7
|
import * as i2 from '@angular/material/expansion';
|
|
7
8
|
import { MAT_EXPANSION_PANEL_DEFAULT_OPTIONS, MatExpansionModule, MatExpansionPanel } from '@angular/material/expansion';
|
|
9
|
+
import * as i5 from '@angular/material/form-field';
|
|
10
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
8
11
|
import * as i3 from '@angular/material/icon';
|
|
9
12
|
import { MatIconModule } from '@angular/material/icon';
|
|
10
13
|
import * as i4 from '@angular/material/button';
|
|
11
14
|
import { MatButtonModule } from '@angular/material/button';
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
15
|
+
import * as i6 from '@angular/material/input';
|
|
16
|
+
import { MatInputModule } from '@angular/material/input';
|
|
17
|
+
import * as i7 from '@angular/material/slide-toggle';
|
|
18
|
+
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
19
|
+
import * as i8 from '@angular/material/tooltip';
|
|
20
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
21
|
+
import { DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
|
|
22
|
+
import { deepMerge, ASYNC_CONFIG_STORAGE, DynamicFormService, ComponentKeyService, DynamicWidgetLoaderDirective, PraxisIconDirective, ComponentMetadataRegistry } from '@praxisui/core';
|
|
23
|
+
import { SettingsPanelService, SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
|
|
24
|
+
import { BehaviorSubject } from 'rxjs';
|
|
25
|
+
import { take } from 'rxjs/operators';
|
|
26
|
+
import { BaseAiAdapter, PraxisAiAssistantComponent } from '@praxisui/ai';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Capabilities catalog for Praxis Expansion (ExpansionMetadata).
|
|
30
|
+
* Paths follow ExpansionMetadata shape (patch merged at config root).
|
|
31
|
+
*/
|
|
32
|
+
const ENUMS = {
|
|
33
|
+
density: ['compact', 'comfortable', 'spacious'],
|
|
34
|
+
displayMode: ['default', 'flat'],
|
|
35
|
+
togglePosition: ['before', 'after'],
|
|
36
|
+
widgetId: ['praxis-dynamic-form', 'praxis-list', 'pdx-material-searchable-select', 'praxis-files-upload'],
|
|
37
|
+
expansionTokenKey: ['header-background-color'],
|
|
38
|
+
};
|
|
39
|
+
const TOKEN_CAPS = ENUMS.expansionTokenKey.map((t) => ({
|
|
40
|
+
path: `appearance.tokens.${t}`,
|
|
41
|
+
category: 'appearance',
|
|
42
|
+
valueKind: 'string',
|
|
43
|
+
description: `Token ${t} (CSS color or var).`,
|
|
44
|
+
safetyNotes: 'Aceita apenas hex color ou var(--token).',
|
|
45
|
+
}));
|
|
46
|
+
const CAPS = [
|
|
47
|
+
{ path: 'appearance', category: 'appearance', valueKind: 'object', description: 'Appearance settings.' },
|
|
48
|
+
{ path: 'appearance.density', category: 'appearance', valueKind: 'enum', allowedValues: ENUMS.density, description: 'Density preset.' },
|
|
49
|
+
{ path: 'appearance.themeClass', category: 'appearance', valueKind: 'string', description: 'Theme CSS class for root.' },
|
|
50
|
+
{ path: 'appearance.customCss', category: 'appearance', valueKind: 'string', description: 'Custom CSS injected into component.', safetyNotes: 'CSS is injected as raw string.' },
|
|
51
|
+
{ path: 'appearance.tokens', category: 'appearance', valueKind: 'object', description: 'Token map for theme overrides.' },
|
|
52
|
+
{ path: 'appearance.tokens.[token]', category: 'appearance', valueKind: 'string', allowedValues: ENUMS.expansionTokenKey, description: 'Token value (CSS or var).', safetyNotes: 'Only keys supported by styleCss().' },
|
|
53
|
+
...TOKEN_CAPS,
|
|
54
|
+
{ path: 'accordion', category: 'accordion', valueKind: 'object', description: 'Accordion behavior settings.' },
|
|
55
|
+
{ path: 'accordion.multi', category: 'accordion', valueKind: 'boolean', description: 'Allow multiple panels open.' },
|
|
56
|
+
{ path: 'accordion.displayMode', category: 'accordion', valueKind: 'enum', allowedValues: ENUMS.displayMode, description: 'Accordion display mode.' },
|
|
57
|
+
{ path: 'accordion.togglePosition', category: 'accordion', valueKind: 'enum', allowedValues: ENUMS.togglePosition, description: 'Toggle icon position.' },
|
|
58
|
+
{ path: 'accordion.hideToggle', category: 'accordion', valueKind: 'boolean', description: 'Hide toggle icon.' },
|
|
59
|
+
{ path: 'accordion.id', category: 'accordion', valueKind: 'string', description: 'Accordion id.' },
|
|
60
|
+
{ path: 'panels', category: 'panels', valueKind: 'array', description: 'Panel list.' },
|
|
61
|
+
{ path: 'panels[]', category: 'panels', valueKind: 'object', description: 'Panel definition.' },
|
|
62
|
+
{ path: 'panels[].id', category: 'panels', valueKind: 'string', description: 'Panel id.' },
|
|
63
|
+
{ path: 'panels[].title', category: 'panels', valueKind: 'string', description: 'Panel title.' },
|
|
64
|
+
{ path: 'panels[].description', category: 'panels', valueKind: 'string', description: 'Panel description.' },
|
|
65
|
+
{ path: 'panels[].disabled', category: 'panels', valueKind: 'boolean', description: 'Disable panel.' },
|
|
66
|
+
{ path: 'panels[].expanded', category: 'panels', valueKind: 'boolean', description: 'Expanded state.' },
|
|
67
|
+
{ path: 'panels[].hideToggle', category: 'panels', valueKind: 'boolean', description: 'Hide toggle icon for panel.' },
|
|
68
|
+
{ path: 'panels[].collapsedHeight', category: 'panels', valueKind: 'string', description: 'Collapsed header height (e.g., 48px).' },
|
|
69
|
+
{ path: 'panels[].expandedHeight', category: 'panels', valueKind: 'string', description: 'Expanded header height (e.g., 64px).' },
|
|
70
|
+
{ path: 'panels[].content', category: 'panels', valueKind: 'array', description: 'Dynamic field metadata list (legacy).' },
|
|
71
|
+
{ path: 'panels[].content[]', category: 'panels', valueKind: 'object', description: 'Dynamic field metadata item.', safetyNotes: 'Use FieldMetadata base when no controlType catalog exists.' },
|
|
72
|
+
{ path: 'panels[].widgets', category: 'panels', valueKind: 'array', description: 'WidgetDefinition list for content.' },
|
|
73
|
+
{ path: 'panels[].widgets[]', category: 'panels', valueKind: 'object', description: 'WidgetDefinition item.' },
|
|
74
|
+
{ path: 'panels[].widgets[].id', category: 'panels', valueKind: 'enum', allowedValues: ENUMS.widgetId, description: 'Component registry id for widget.' },
|
|
75
|
+
{ path: 'panels[].widgets[].inputs', category: 'panels', valueKind: 'object', description: 'Inputs bound into the widget instance.' },
|
|
76
|
+
{ path: 'panels[].widgets[].outputs', category: 'panels', valueKind: 'object', description: 'Outputs mapped to actions.' },
|
|
77
|
+
{ path: 'panels[].widgets[].outputs.[outputName]', category: 'panels', valueKind: 'object', description: 'Output action mapping (ActionDefinition or "emit").' },
|
|
78
|
+
{ path: 'panels[].widgets[].bindingOrder', category: 'panels', valueKind: 'array', description: 'Explicit input binding order.' },
|
|
79
|
+
{ path: 'panels[].widgets[].bindingOrder[]', category: 'panels', valueKind: 'string', description: 'Input name applied first.' },
|
|
80
|
+
{ path: 'panels[].actionButtons', category: 'actions', valueKind: 'array', description: 'Action buttons at panel footer.' },
|
|
81
|
+
{ path: 'panels[].actionButtons[]', category: 'actions', valueKind: 'object', description: 'Action button definition.' },
|
|
82
|
+
{ path: 'panels[].actionButtons[].icon', category: 'actions', valueKind: 'string', description: 'Action icon.' },
|
|
83
|
+
{ path: 'panels[].actionButtons[].label', category: 'actions', valueKind: 'string', description: 'Action label.' },
|
|
84
|
+
{ path: 'panels[].actionButtons[].action', category: 'actions', valueKind: 'string', description: 'Action identifier payload.' },
|
|
85
|
+
];
|
|
86
|
+
const EXPANSION_AI_CAPABILITIES = {
|
|
87
|
+
version: 'v1.1',
|
|
88
|
+
enums: ENUMS,
|
|
89
|
+
targets: [
|
|
90
|
+
'praxis-expansion',
|
|
91
|
+
'mat-accordion',
|
|
92
|
+
'expansion-panel',
|
|
93
|
+
'praxis-expansion-config-editor',
|
|
94
|
+
],
|
|
95
|
+
notes: [
|
|
96
|
+
'panels[] should be merged by id or title to avoid replacing all panels.',
|
|
97
|
+
'appearance.customCss is injected into a <style> tag; avoid unsafe CSS from untrusted sources.',
|
|
98
|
+
'appearance.tokens supports limited keys used by styleCss().',
|
|
99
|
+
'panels[].widgets[].id must be a ComponentMetadataRegistry id.',
|
|
100
|
+
'If a field controlType lacks a dedicated catalog, treat it as FieldMetadata base.',
|
|
101
|
+
],
|
|
102
|
+
capabilities: CAPS,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
class ExpansionAiAdapter extends BaseAiAdapter {
|
|
106
|
+
expansion;
|
|
107
|
+
componentName = 'Praxis Expansion';
|
|
108
|
+
constructor(expansion) {
|
|
109
|
+
super();
|
|
110
|
+
this.expansion = expansion;
|
|
111
|
+
}
|
|
112
|
+
getCurrentConfig() {
|
|
113
|
+
const current = this.expansion.config || {};
|
|
114
|
+
return this.cloneConfig(current);
|
|
115
|
+
}
|
|
116
|
+
getCapabilities() {
|
|
117
|
+
return EXPANSION_AI_CAPABILITIES.capabilities;
|
|
118
|
+
}
|
|
119
|
+
getRuntimeState() {
|
|
120
|
+
const panels = this.expansion.config?.panels || [];
|
|
121
|
+
return {
|
|
122
|
+
panelsCount: panels.length,
|
|
123
|
+
expandedCount: panels.filter((p) => p.expanded).length,
|
|
124
|
+
multi: this.expansion.config?.accordion?.multi ?? false,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
createSnapshot() {
|
|
128
|
+
return this.getCurrentConfig();
|
|
129
|
+
}
|
|
130
|
+
async restoreSnapshot(snapshot) {
|
|
131
|
+
if (!snapshot)
|
|
132
|
+
return;
|
|
133
|
+
this.applyConfig(this.cloneConfig(snapshot));
|
|
134
|
+
}
|
|
135
|
+
async applyPatch(patch) {
|
|
136
|
+
try {
|
|
137
|
+
const current = this.getCurrentConfig();
|
|
138
|
+
const next = this.smartMergeExpansionConfig(current, patch);
|
|
139
|
+
this.applyConfig(next);
|
|
140
|
+
return { success: true };
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
const message = error instanceof Error ? error.message : 'Unknown error applying patch';
|
|
144
|
+
return { success: false, error: message };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
applyConfig(config) {
|
|
148
|
+
const apply = this.expansion.applyConfigFromAdapter;
|
|
149
|
+
if (typeof apply === 'function') {
|
|
150
|
+
apply.call(this.expansion, config);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.expansion.config = config;
|
|
154
|
+
}
|
|
155
|
+
smartMergeExpansionConfig(base, patch) {
|
|
156
|
+
const result = deepMerge(base, patch);
|
|
157
|
+
if (patch.panels && Array.isArray(patch.panels)) {
|
|
158
|
+
const merged = this.mergeByKey(base.panels || [], patch.panels, (p) => p.id || p.title || '');
|
|
159
|
+
result.panels = merged;
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
mergeByKey(baseArr, patchArr, keyFn) {
|
|
164
|
+
const merged = baseArr.map((orig) => {
|
|
165
|
+
const key = keyFn(orig);
|
|
166
|
+
const match = key ? patchArr.find((p) => keyFn(p) === key) : undefined;
|
|
167
|
+
return match ? deepMerge(orig, match) : orig;
|
|
168
|
+
});
|
|
169
|
+
patchArr.forEach((item) => {
|
|
170
|
+
const key = keyFn(item);
|
|
171
|
+
if (!key || !baseArr.find((o) => keyFn(o) === key)) {
|
|
172
|
+
merged.push(item);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return merged;
|
|
176
|
+
}
|
|
177
|
+
cloneConfig(config) {
|
|
178
|
+
try {
|
|
179
|
+
return structuredClone(config);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return JSON.parse(JSON.stringify(config));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
14
186
|
|
|
15
187
|
class PraxisExpansion {
|
|
16
188
|
config;
|
|
17
189
|
expansionId;
|
|
190
|
+
componentInstanceId;
|
|
18
191
|
context = {};
|
|
19
192
|
strictValidation = true;
|
|
20
|
-
|
|
193
|
+
enableCustomization = false;
|
|
21
194
|
defaultOptions;
|
|
22
195
|
opened = new EventEmitter();
|
|
23
196
|
closed = new EventEmitter();
|
|
@@ -27,26 +200,202 @@ class PraxisExpansion {
|
|
|
27
200
|
destroyed = new EventEmitter();
|
|
28
201
|
widgetEvent = new EventEmitter();
|
|
29
202
|
settings = inject(SettingsPanelService);
|
|
30
|
-
storage = inject(
|
|
203
|
+
storage = inject(ASYNC_CONFIG_STORAGE);
|
|
204
|
+
cdr = inject(ChangeDetectorRef);
|
|
31
205
|
destroyRef = inject(DestroyRef);
|
|
206
|
+
dynamicForm = inject(DynamicFormService);
|
|
207
|
+
componentKeys = inject(ComponentKeyService);
|
|
208
|
+
route = (() => { try {
|
|
209
|
+
return inject(ActivatedRoute);
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return undefined;
|
|
213
|
+
} })();
|
|
214
|
+
warnedMissingId = false;
|
|
215
|
+
panelForms = new Map();
|
|
216
|
+
aiAdapter = new ExpansionAiAdapter(this);
|
|
32
217
|
accordionRef;
|
|
33
218
|
panels;
|
|
34
219
|
injectedDefaults = inject(MAT_EXPANSION_PANEL_DEFAULT_OPTIONS, { optional: true });
|
|
35
220
|
hasMultiple = () => (this.config?.panels?.length || 0) > 1;
|
|
36
221
|
single = () => (this.config?.panels && this.config.panels[0]) || null;
|
|
222
|
+
ngOnInit() {
|
|
223
|
+
const key = this.storageKey();
|
|
224
|
+
if (!key)
|
|
225
|
+
return;
|
|
226
|
+
this.storage.loadConfig(key).pipe(take(1)).subscribe((stored) => {
|
|
227
|
+
if (!stored)
|
|
228
|
+
return;
|
|
229
|
+
this.config = stored;
|
|
230
|
+
this.buildPanelForms();
|
|
231
|
+
this.cdr.markForCheck();
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
ngOnChanges(changes) {
|
|
235
|
+
if ('config' in changes) {
|
|
236
|
+
this.buildPanelForms();
|
|
237
|
+
this.persistConfig(this.config);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
37
240
|
styleCss() {
|
|
38
241
|
const t = this.config?.appearance?.tokens;
|
|
39
|
-
|
|
242
|
+
const appearance = this.config?.appearance;
|
|
243
|
+
if (!t && !appearance?.container && !appearance?.header && !appearance?.states)
|
|
40
244
|
return null;
|
|
41
245
|
const scope = `.praxis-expansion-root[data-expansion-id="${(this.expansionId || 'default').replace(/"/g, '')}"]`;
|
|
42
246
|
const rules = [];
|
|
43
|
-
const push = (selector, decls) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
247
|
+
const push = (selector, decls) => {
|
|
248
|
+
rules.push(`${scope} ${selector}{${decls.join('')}}`);
|
|
249
|
+
};
|
|
250
|
+
const isSafeColor = (value) => /^#[0-9a-fA-F]{3,8}$/.test(value)
|
|
251
|
+
|| /^var\(--[\w-]+\)$/.test(value)
|
|
252
|
+
|| /^(rgb|rgba|hsl|hsla)\(/.test(value)
|
|
253
|
+
|| /^color-mix\(/.test(value);
|
|
254
|
+
if (t) {
|
|
255
|
+
const panelBg = t['panel-background-color'];
|
|
256
|
+
if (panelBg && isSafeColor(panelBg)) {
|
|
257
|
+
push(' .mat-expansion-panel', [`background:${panelBg}!important;`]);
|
|
258
|
+
}
|
|
259
|
+
const panelBorder = t['panel-border-color'];
|
|
260
|
+
if (panelBorder && isSafeColor(panelBorder)) {
|
|
261
|
+
push(' .mat-expansion-panel', [`border-color:${panelBorder}!important;`]);
|
|
262
|
+
}
|
|
263
|
+
const headerBg = t['header-background-color'];
|
|
264
|
+
if (headerBg && isSafeColor(headerBg)) {
|
|
265
|
+
push(' .mat-expansion-panel-header', [`background-color:${headerBg}!important;`]);
|
|
266
|
+
}
|
|
267
|
+
const headerText = t['header-text-color'];
|
|
268
|
+
if (headerText && isSafeColor(headerText)) {
|
|
269
|
+
push(' .mat-expansion-panel-header', [`color:${headerText}!important;`]);
|
|
270
|
+
}
|
|
271
|
+
const descText = t['description-text-color'];
|
|
272
|
+
if (descText && isSafeColor(descText)) {
|
|
273
|
+
push(' .mat-expansion-panel-header-description', [`color:${descText}!important;`]);
|
|
274
|
+
}
|
|
275
|
+
const bodyText = t['body-text-color'];
|
|
276
|
+
if (bodyText && isSafeColor(bodyText)) {
|
|
277
|
+
push(' .mat-expansion-panel-body', [`color:${bodyText}!important;`]);
|
|
278
|
+
}
|
|
279
|
+
const actionBorder = t['action-row-border-color'];
|
|
280
|
+
if (actionBorder && isSafeColor(actionBorder)) {
|
|
281
|
+
push(' .mat-action-row', [`border-top-color:${actionBorder}!important;`]);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (appearance?.container) {
|
|
285
|
+
const container = appearance.container;
|
|
286
|
+
const decls = [];
|
|
287
|
+
if (container.background)
|
|
288
|
+
decls.push(`background:${container.background};`);
|
|
289
|
+
if (container.borderColor)
|
|
290
|
+
decls.push(`border-color:${container.borderColor};`);
|
|
291
|
+
if (container.borderWidth)
|
|
292
|
+
decls.push(`border-width:${container.borderWidth};`);
|
|
293
|
+
if (container.borderStyle)
|
|
294
|
+
decls.push(`border-style:${container.borderStyle};`);
|
|
295
|
+
if (container.borderRadius)
|
|
296
|
+
decls.push(`border-radius:${container.borderRadius};`);
|
|
297
|
+
if (container.shadow)
|
|
298
|
+
decls.push(`box-shadow:${container.shadow};`);
|
|
299
|
+
if (container.padding)
|
|
300
|
+
decls.push(`padding:${container.padding};`);
|
|
301
|
+
if (decls.length) {
|
|
302
|
+
push('', decls);
|
|
303
|
+
}
|
|
304
|
+
if (container.panelGap) {
|
|
305
|
+
push(' .mat-expansion-panel:not(:last-child)', [`margin-bottom:${container.panelGap};`]);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (appearance?.header) {
|
|
309
|
+
const header = appearance.header;
|
|
310
|
+
const headerDecls = [];
|
|
311
|
+
if (header.background)
|
|
312
|
+
headerDecls.push(`background:${header.background}!important;`);
|
|
313
|
+
if (header.textColor)
|
|
314
|
+
headerDecls.push(`color:${header.textColor}!important;`);
|
|
315
|
+
if (header.height)
|
|
316
|
+
headerDecls.push(`min-height:${header.height};`);
|
|
317
|
+
if (header.padding)
|
|
318
|
+
headerDecls.push(`padding:${header.padding};`);
|
|
319
|
+
if (header.gap)
|
|
320
|
+
headerDecls.push(`column-gap:${header.gap};`);
|
|
321
|
+
if (headerDecls.length)
|
|
322
|
+
push(' .mat-expansion-panel-header', headerDecls);
|
|
323
|
+
if (header.fontFamily) {
|
|
324
|
+
push(' .mat-expansion-panel-header-title', [`font-family:${header.fontFamily};`]);
|
|
325
|
+
push(' .mat-expansion-panel-header-description', [`font-family:${header.fontFamily};`]);
|
|
326
|
+
}
|
|
327
|
+
const titleDecls = [];
|
|
328
|
+
if (header.titleColor)
|
|
329
|
+
titleDecls.push(`color:${header.titleColor}!important;`);
|
|
330
|
+
if (header.titleSize)
|
|
331
|
+
titleDecls.push(`font-size:${header.titleSize};`);
|
|
332
|
+
if (header.titleWeight)
|
|
333
|
+
titleDecls.push(`font-weight:${header.titleWeight};`);
|
|
334
|
+
if (titleDecls.length)
|
|
335
|
+
push(' .mat-expansion-panel-header-title', titleDecls);
|
|
336
|
+
const descDecls = [];
|
|
337
|
+
if (header.descriptionColor)
|
|
338
|
+
descDecls.push(`color:${header.descriptionColor}!important;`);
|
|
339
|
+
if (header.descriptionSize)
|
|
340
|
+
descDecls.push(`font-size:${header.descriptionSize};`);
|
|
341
|
+
if (header.descriptionWeight)
|
|
342
|
+
descDecls.push(`font-weight:${header.descriptionWeight};`);
|
|
343
|
+
if (descDecls.length)
|
|
344
|
+
push(' .mat-expansion-panel-header-description', descDecls);
|
|
345
|
+
const iconDecls = [];
|
|
346
|
+
if (header.toggleIconColor)
|
|
347
|
+
iconDecls.push(`border-color:${header.toggleIconColor}!important;`);
|
|
348
|
+
if (iconDecls.length)
|
|
349
|
+
push(' .mat-expansion-indicator::after', iconDecls);
|
|
350
|
+
if (header.toggleIconSize) {
|
|
351
|
+
push(' .mat-expansion-indicator::after', [
|
|
352
|
+
`width:${header.toggleIconSize};`,
|
|
353
|
+
`height:${header.toggleIconSize};`,
|
|
354
|
+
]);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (appearance?.states) {
|
|
358
|
+
const states = appearance.states;
|
|
359
|
+
if (states.hover) {
|
|
360
|
+
const decls = [];
|
|
361
|
+
if (states.hover.headerBackground)
|
|
362
|
+
decls.push(`background:${states.hover.headerBackground}!important;`);
|
|
363
|
+
if (states.hover.textColor)
|
|
364
|
+
decls.push(`color:${states.hover.textColor}!important;`);
|
|
365
|
+
if (decls.length)
|
|
366
|
+
push(' .mat-expansion-panel-header:hover', decls);
|
|
367
|
+
}
|
|
368
|
+
if (states.expanded) {
|
|
369
|
+
const decls = [];
|
|
370
|
+
if (states.expanded.headerBackground)
|
|
371
|
+
decls.push(`background:${states.expanded.headerBackground}!important;`);
|
|
372
|
+
if (states.expanded.textColor)
|
|
373
|
+
decls.push(`color:${states.expanded.textColor}!important;`);
|
|
374
|
+
if (decls.length)
|
|
375
|
+
push(' .mat-expansion-panel.mat-expanded > .mat-expansion-panel-header', decls);
|
|
376
|
+
if (states.expanded.accentBarColor) {
|
|
377
|
+
push(' .mat-expansion-panel.mat-expanded > .mat-expansion-panel-header', [
|
|
378
|
+
'position:relative;',
|
|
379
|
+
]);
|
|
380
|
+
push(' .mat-expansion-panel.mat-expanded > .mat-expansion-panel-header::before', [
|
|
381
|
+
'content:"";',
|
|
382
|
+
'position:absolute;',
|
|
383
|
+
'left:0;',
|
|
384
|
+
'top:0;',
|
|
385
|
+
'bottom:0;',
|
|
386
|
+
'width:4px;',
|
|
387
|
+
`background:${states.expanded.accentBarColor};`,
|
|
388
|
+
]);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (states.disabled) {
|
|
392
|
+
const decls = [];
|
|
393
|
+
if (states.disabled.headerBackground)
|
|
394
|
+
decls.push(`background:${states.disabled.headerBackground}!important;`);
|
|
395
|
+
if (states.disabled.textColor)
|
|
396
|
+
decls.push(`color:${states.disabled.textColor}!important;`);
|
|
397
|
+
if (decls.length)
|
|
398
|
+
push(' .mat-expansion-panel.mat-expansion-panel-disabled .mat-expansion-panel-header', decls);
|
|
50
399
|
}
|
|
51
400
|
}
|
|
52
401
|
if (rules.length === 0)
|
|
@@ -101,9 +450,29 @@ class PraxisExpansion {
|
|
|
101
450
|
const base = p?.id || `${this.expansionId || 'exp'}-panel-${index + 1}`;
|
|
102
451
|
return base.replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
103
452
|
}
|
|
453
|
+
panelFormFor(panel, index) {
|
|
454
|
+
const key = this.panelKey(panel, index);
|
|
455
|
+
const existing = this.panelForms.get(key);
|
|
456
|
+
if (existing)
|
|
457
|
+
return existing;
|
|
458
|
+
const fields = panel.content ?? [];
|
|
459
|
+
const form = this.dynamicForm.createFormGroupFromMetadata(fields);
|
|
460
|
+
this.panelForms.set(key, form);
|
|
461
|
+
return form;
|
|
462
|
+
}
|
|
463
|
+
applyConfigFromAdapter(next) {
|
|
464
|
+
this.config = next;
|
|
465
|
+
this.buildPanelForms();
|
|
466
|
+
const key = this.storageKey();
|
|
467
|
+
if (key) {
|
|
468
|
+
this.storage.saveConfig(key, this.config).pipe(take(1)).subscribe({ error: () => { } });
|
|
469
|
+
}
|
|
470
|
+
this.cdr.markForCheck();
|
|
471
|
+
}
|
|
104
472
|
openEditor() {
|
|
473
|
+
const key = this.storageKey() || this.expansionId || 'default';
|
|
105
474
|
const ref = this.settings.open({
|
|
106
|
-
id: `praxis-expansion-editor:${
|
|
475
|
+
id: `praxis-expansion-editor:${key}`,
|
|
107
476
|
title: 'Configurar Painéis',
|
|
108
477
|
content: { component: PraxisExpansionConfigEditor, inputs: { config: this.config, expansionId: this.expansionId } },
|
|
109
478
|
});
|
|
@@ -111,21 +480,71 @@ class PraxisExpansion {
|
|
|
111
480
|
const nextCfg = value?.config || value;
|
|
112
481
|
if (nextCfg) {
|
|
113
482
|
this.config = { ...nextCfg };
|
|
114
|
-
|
|
115
|
-
|
|
483
|
+
this.buildPanelForms();
|
|
484
|
+
const storageKey = this.storageKey();
|
|
485
|
+
if (storageKey) {
|
|
486
|
+
this.storage.saveConfig(storageKey, this.config).pipe(take(1)).subscribe({ error: () => { } });
|
|
487
|
+
}
|
|
488
|
+
this.cdr.markForCheck();
|
|
116
489
|
}
|
|
117
490
|
};
|
|
118
491
|
ref.applied$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(apply);
|
|
119
492
|
ref.saved$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(apply);
|
|
120
493
|
}
|
|
121
494
|
storageKey() {
|
|
122
|
-
|
|
495
|
+
const id = this.componentKeyId();
|
|
496
|
+
return id ? `expansion:${id}` : null;
|
|
497
|
+
}
|
|
498
|
+
persistConfig(config) {
|
|
499
|
+
if (!config)
|
|
500
|
+
return;
|
|
501
|
+
const key = this.storageKey();
|
|
502
|
+
if (!key)
|
|
503
|
+
return;
|
|
504
|
+
this.storage.saveConfig(key, config).pipe(take(1)).subscribe({ error: () => { } });
|
|
123
505
|
}
|
|
124
506
|
emitAction(p, index, action) {
|
|
125
507
|
this.widgetEvent.emit({ panelId: p.id, panelIndex: index, sourceId: 'praxis-expansion', output: 'action', payload: { action } });
|
|
126
508
|
}
|
|
127
|
-
|
|
128
|
-
|
|
509
|
+
panelKey(panel, index) {
|
|
510
|
+
return panel.id ?? `panel-${index}`;
|
|
511
|
+
}
|
|
512
|
+
buildPanelForms() {
|
|
513
|
+
const previous = new Map(this.panelForms);
|
|
514
|
+
this.panelForms.clear();
|
|
515
|
+
const panels = this.config?.panels ?? [];
|
|
516
|
+
panels.forEach((panel, index) => {
|
|
517
|
+
const fields = panel.content ?? [];
|
|
518
|
+
if (!fields.length)
|
|
519
|
+
return;
|
|
520
|
+
const key = this.panelKey(panel, index);
|
|
521
|
+
const form = this.dynamicForm.createFormGroupFromMetadata(fields);
|
|
522
|
+
const previousValues = previous.get(key)?.getRawValue?.() ?? {};
|
|
523
|
+
form.patchValue(previousValues);
|
|
524
|
+
this.panelForms.set(key, form);
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
componentKeyId() {
|
|
528
|
+
const key = this.componentKeys.buildComponentId({
|
|
529
|
+
componentType: 'praxis-expansion',
|
|
530
|
+
componentId: this.expansionId,
|
|
531
|
+
instanceKey: this.componentInstanceId,
|
|
532
|
+
componentRef: this,
|
|
533
|
+
route: this.route,
|
|
534
|
+
requireComponentId: true,
|
|
535
|
+
});
|
|
536
|
+
if (!key)
|
|
537
|
+
this.warnMissingId();
|
|
538
|
+
return key;
|
|
539
|
+
}
|
|
540
|
+
warnMissingId() {
|
|
541
|
+
if (this.warnedMissingId)
|
|
542
|
+
return;
|
|
543
|
+
this.warnedMissingId = true;
|
|
544
|
+
console.warn('[PraxisExpansion] expansionId is required for config persistence.');
|
|
545
|
+
}
|
|
546
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisExpansion, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
547
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisExpansion, isStandalone: true, selector: "praxis-expansion", inputs: { config: "config", expansionId: "expansionId", componentInstanceId: "componentInstanceId", context: "context", strictValidation: "strictValidation", enableCustomization: "enableCustomization", defaultOptions: "defaultOptions" }, outputs: { opened: "opened", closed: "closed", expandedChange: "expandedChange", afterExpand: "afterExpand", afterCollapse: "afterCollapse", destroyed: "destroyed", widgetEvent: "widgetEvent" }, viewQueries: [{ propertyName: "accordionRef", first: true, predicate: ["accordion"], descendants: true }, { propertyName: "panels", predicate: ["panel"], descendants: true, read: MatExpansionPanel }], usesOnChanges: true, ngImport: i0, template: `
|
|
129
548
|
<div
|
|
130
549
|
class="praxis-expansion-root"
|
|
131
550
|
[class.density-compact]="config?.appearance?.density === 'compact'"
|
|
@@ -137,6 +556,12 @@ class PraxisExpansion {
|
|
|
137
556
|
<style *ngIf="config?.appearance?.customCss" [innerHTML]="config?.appearance?.customCss"></style>
|
|
138
557
|
<style *ngIf="styleCss() as s" [innerHTML]="s"></style>
|
|
139
558
|
|
|
559
|
+
@if (enableCustomization) {
|
|
560
|
+
<div class="expansion-ai-assistant">
|
|
561
|
+
<praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
|
|
562
|
+
</div>
|
|
563
|
+
}
|
|
564
|
+
|
|
140
565
|
@if (hasMultiple()) {
|
|
141
566
|
<mat-accordion
|
|
142
567
|
#accordion
|
|
@@ -170,6 +595,14 @@ class PraxisExpansion {
|
|
|
170
595
|
</mat-expansion-panel-header>
|
|
171
596
|
|
|
172
597
|
<ng-template matExpansionPanelContent>
|
|
598
|
+
@if (p.content?.length) {
|
|
599
|
+
<ng-container
|
|
600
|
+
dynamicFieldLoader
|
|
601
|
+
[fields]="p.content ?? []"
|
|
602
|
+
[formGroup]="panelFormFor(p, i)"
|
|
603
|
+
></ng-container>
|
|
604
|
+
}
|
|
605
|
+
|
|
173
606
|
@if (p.widgets?.length) {
|
|
174
607
|
@for (w of p.widgets; let wi = $index; track wi) {
|
|
175
608
|
<ng-container
|
|
@@ -219,6 +652,14 @@ class PraxisExpansion {
|
|
|
219
652
|
</mat-expansion-panel-header>
|
|
220
653
|
|
|
221
654
|
<ng-template matExpansionPanelContent>
|
|
655
|
+
@if (p.content?.length) {
|
|
656
|
+
<ng-container
|
|
657
|
+
dynamicFieldLoader
|
|
658
|
+
[fields]="p.content ?? []"
|
|
659
|
+
[formGroup]="panelFormFor(p, 0)"
|
|
660
|
+
></ng-container>
|
|
661
|
+
}
|
|
662
|
+
|
|
222
663
|
@if (p.widgets?.length) {
|
|
223
664
|
@for (w of p.widgets; let wi = $index; track wi) {
|
|
224
665
|
<ng-container
|
|
@@ -245,7 +686,7 @@ class PraxisExpansion {
|
|
|
245
686
|
} @else {
|
|
246
687
|
<div class="praxis-expansion-empty">
|
|
247
688
|
<span>Nenhum painel configurado</span>
|
|
248
|
-
<button mat-stroked-button color="primary" *ngIf="
|
|
689
|
+
<button mat-stroked-button color="primary" *ngIf="enableCustomization" (click)="openEditor()">
|
|
249
690
|
<mat-icon [praxisIcon]="'tune'"></mat-icon> Configurar
|
|
250
691
|
</button>
|
|
251
692
|
</div>
|
|
@@ -254,7 +695,7 @@ class PraxisExpansion {
|
|
|
254
695
|
</div>
|
|
255
696
|
<!-- Edit button -->
|
|
256
697
|
<button
|
|
257
|
-
*ngIf="
|
|
698
|
+
*ngIf="enableCustomization"
|
|
258
699
|
mat-fab
|
|
259
700
|
class="edit-fab"
|
|
260
701
|
aria-label="Editar painéis"
|
|
@@ -262,17 +703,19 @@ class PraxisExpansion {
|
|
|
262
703
|
>
|
|
263
704
|
<mat-icon fontIcon="edit"></mat-icon>
|
|
264
705
|
</button>
|
|
265
|
-
`, isInline: true, styles: [":host{display:block;position:relative}.praxis-expansion-root{display:block}.praxis-expansion-empty{display:flex;gap:8px;align-items:center;padding:8px;
|
|
706
|
+
`, isInline: true, styles: [":host{display:block;position:relative;color:var(--md-sys-color-on-surface)}.praxis-expansion-root{display:block;--p-exp-surface: var(--md-sys-color-surface);--p-exp-surface-container: var(--md-sys-color-surface-container);--p-exp-border: var(--md-sys-color-outline-variant);--p-exp-text: var(--md-sys-color-on-surface);--p-exp-text-muted: var(--md-sys-color-on-surface-variant);--p-exp-focus: var(--md-sys-color-primary);--p-exp-radius: 12px}.mat-expansion-panel{background:var(--p-exp-surface);border:1px solid var(--p-exp-border);border-radius:var(--p-exp-radius);overflow:hidden}.mat-expansion-panel:not(:last-child){margin-bottom:var(--p-exp-panel-gap, 12px)}.mat-expansion-panel-header{background:var(--p-exp-surface-container);color:var(--p-exp-text)}.mat-expansion-panel-header:focus-visible{outline:2px solid var(--p-exp-focus);outline-offset:-2px}.mat-expansion-panel-header-title{font-weight:600}.mat-expansion-panel-header-description{color:var(--p-exp-text-muted)}.mat-expansion-panel-body{padding:12px 16px 16px}.mat-action-row{border-top:1px solid var(--p-exp-border)}.density-compact .mat-expansion-panel-body{padding:8px 12px 12px}.density-compact .mat-expansion-panel-header{min-height:40px;padding:0 12px}.density-comfortable .mat-expansion-panel-body{padding:12px 16px 16px}.density-comfortable .mat-expansion-panel-header{min-height:48px;padding:0 16px}.density-spacious .mat-expansion-panel-body{padding:16px 20px 20px}.density-spacious .mat-expansion-panel-header{min-height:56px;padding:0 20px}.praxis-expansion-empty{display:flex;gap:8px;align-items:center;padding:8px 12px;color:var(--p-exp-text-muted)}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.expansion-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i2.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i2.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "directive", type: i2.MatExpansionPanelActionRow, selector: "mat-action-row" }, { kind: "component", type: i2.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i2.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i2.MatExpansionPanelDescription, selector: "mat-panel-description" }, { kind: "directive", type: i2.MatExpansionPanelContent, selector: "ng-template[matExpansionPanelContent]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent"], exportAs: ["dynamicWidgetLoader"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
266
707
|
}
|
|
267
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
708
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisExpansion, decorators: [{
|
|
268
709
|
type: Component,
|
|
269
710
|
args: [{ selector: 'praxis-expansion', standalone: true, imports: [
|
|
270
711
|
CommonModule,
|
|
271
712
|
MatExpansionModule,
|
|
272
713
|
MatIconModule,
|
|
273
714
|
MatButtonModule,
|
|
715
|
+
DynamicFieldLoaderDirective,
|
|
274
716
|
DynamicWidgetLoaderDirective,
|
|
275
717
|
PraxisIconDirective,
|
|
718
|
+
PraxisAiAssistantComponent,
|
|
276
719
|
], template: `
|
|
277
720
|
<div
|
|
278
721
|
class="praxis-expansion-root"
|
|
@@ -285,6 +728,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
285
728
|
<style *ngIf="config?.appearance?.customCss" [innerHTML]="config?.appearance?.customCss"></style>
|
|
286
729
|
<style *ngIf="styleCss() as s" [innerHTML]="s"></style>
|
|
287
730
|
|
|
731
|
+
@if (enableCustomization) {
|
|
732
|
+
<div class="expansion-ai-assistant">
|
|
733
|
+
<praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
|
|
734
|
+
</div>
|
|
735
|
+
}
|
|
736
|
+
|
|
288
737
|
@if (hasMultiple()) {
|
|
289
738
|
<mat-accordion
|
|
290
739
|
#accordion
|
|
@@ -318,6 +767,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
318
767
|
</mat-expansion-panel-header>
|
|
319
768
|
|
|
320
769
|
<ng-template matExpansionPanelContent>
|
|
770
|
+
@if (p.content?.length) {
|
|
771
|
+
<ng-container
|
|
772
|
+
dynamicFieldLoader
|
|
773
|
+
[fields]="p.content ?? []"
|
|
774
|
+
[formGroup]="panelFormFor(p, i)"
|
|
775
|
+
></ng-container>
|
|
776
|
+
}
|
|
777
|
+
|
|
321
778
|
@if (p.widgets?.length) {
|
|
322
779
|
@for (w of p.widgets; let wi = $index; track wi) {
|
|
323
780
|
<ng-container
|
|
@@ -367,6 +824,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
367
824
|
</mat-expansion-panel-header>
|
|
368
825
|
|
|
369
826
|
<ng-template matExpansionPanelContent>
|
|
827
|
+
@if (p.content?.length) {
|
|
828
|
+
<ng-container
|
|
829
|
+
dynamicFieldLoader
|
|
830
|
+
[fields]="p.content ?? []"
|
|
831
|
+
[formGroup]="panelFormFor(p, 0)"
|
|
832
|
+
></ng-container>
|
|
833
|
+
}
|
|
834
|
+
|
|
370
835
|
@if (p.widgets?.length) {
|
|
371
836
|
@for (w of p.widgets; let wi = $index; track wi) {
|
|
372
837
|
<ng-container
|
|
@@ -393,7 +858,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
393
858
|
} @else {
|
|
394
859
|
<div class="praxis-expansion-empty">
|
|
395
860
|
<span>Nenhum painel configurado</span>
|
|
396
|
-
<button mat-stroked-button color="primary" *ngIf="
|
|
861
|
+
<button mat-stroked-button color="primary" *ngIf="enableCustomization" (click)="openEditor()">
|
|
397
862
|
<mat-icon [praxisIcon]="'tune'"></mat-icon> Configurar
|
|
398
863
|
</button>
|
|
399
864
|
</div>
|
|
@@ -402,7 +867,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
402
867
|
</div>
|
|
403
868
|
<!-- Edit button -->
|
|
404
869
|
<button
|
|
405
|
-
*ngIf="
|
|
870
|
+
*ngIf="enableCustomization"
|
|
406
871
|
mat-fab
|
|
407
872
|
class="edit-fab"
|
|
408
873
|
aria-label="Editar painéis"
|
|
@@ -410,16 +875,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
410
875
|
>
|
|
411
876
|
<mat-icon fontIcon="edit"></mat-icon>
|
|
412
877
|
</button>
|
|
413
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative}.praxis-expansion-root{display:block}.praxis-expansion-empty{display:flex;gap:8px;align-items:center;padding:8px;
|
|
878
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative;color:var(--md-sys-color-on-surface)}.praxis-expansion-root{display:block;--p-exp-surface: var(--md-sys-color-surface);--p-exp-surface-container: var(--md-sys-color-surface-container);--p-exp-border: var(--md-sys-color-outline-variant);--p-exp-text: var(--md-sys-color-on-surface);--p-exp-text-muted: var(--md-sys-color-on-surface-variant);--p-exp-focus: var(--md-sys-color-primary);--p-exp-radius: 12px}.mat-expansion-panel{background:var(--p-exp-surface);border:1px solid var(--p-exp-border);border-radius:var(--p-exp-radius);overflow:hidden}.mat-expansion-panel:not(:last-child){margin-bottom:var(--p-exp-panel-gap, 12px)}.mat-expansion-panel-header{background:var(--p-exp-surface-container);color:var(--p-exp-text)}.mat-expansion-panel-header:focus-visible{outline:2px solid var(--p-exp-focus);outline-offset:-2px}.mat-expansion-panel-header-title{font-weight:600}.mat-expansion-panel-header-description{color:var(--p-exp-text-muted)}.mat-expansion-panel-body{padding:12px 16px 16px}.mat-action-row{border-top:1px solid var(--p-exp-border)}.density-compact .mat-expansion-panel-body{padding:8px 12px 12px}.density-compact .mat-expansion-panel-header{min-height:40px;padding:0 12px}.density-comfortable .mat-expansion-panel-body{padding:12px 16px 16px}.density-comfortable .mat-expansion-panel-header{min-height:48px;padding:0 16px}.density-spacious .mat-expansion-panel-body{padding:16px 20px 20px}.density-spacious .mat-expansion-panel-header{min-height:56px;padding:0 20px}.praxis-expansion-empty{display:flex;gap:8px;align-items:center;padding:8px 12px;color:var(--p-exp-text-muted)}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.expansion-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}\n"] }]
|
|
414
879
|
}], propDecorators: { config: [{
|
|
415
880
|
type: Input
|
|
416
881
|
}], expansionId: [{
|
|
882
|
+
type: Input,
|
|
883
|
+
args: [{ required: true }]
|
|
884
|
+
}], componentInstanceId: [{
|
|
417
885
|
type: Input
|
|
418
886
|
}], context: [{
|
|
419
887
|
type: Input
|
|
420
888
|
}], strictValidation: [{
|
|
421
889
|
type: Input
|
|
422
|
-
}],
|
|
890
|
+
}], enableCustomization: [{
|
|
423
891
|
type: Input
|
|
424
892
|
}], defaultOptions: [{
|
|
425
893
|
type: Input
|
|
@@ -448,15 +916,130 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
448
916
|
class PraxisExpansionConfigEditor {
|
|
449
917
|
config;
|
|
450
918
|
expansionId;
|
|
919
|
+
tokensError = '';
|
|
920
|
+
isDirty$ = new BehaviorSubject(false);
|
|
921
|
+
isValid$ = new BehaviorSubject(true);
|
|
922
|
+
isBusy$ = new BehaviorSubject(false);
|
|
923
|
+
initialJson = '';
|
|
924
|
+
hasInitializedSnapshot = false;
|
|
925
|
+
constructor(injected) {
|
|
926
|
+
const injectedConfig = injected?.config;
|
|
927
|
+
if (injectedConfig) {
|
|
928
|
+
this.config = injectedConfig;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
ngOnChanges(changes) {
|
|
932
|
+
if (changes['config'] && this.config && !this.hasInitializedSnapshot) {
|
|
933
|
+
this.captureInitialSnapshot(this.config);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
getSettingsValue() {
|
|
937
|
+
return this.config;
|
|
938
|
+
}
|
|
939
|
+
reset() {
|
|
940
|
+
if (!this.initialJson)
|
|
941
|
+
return;
|
|
942
|
+
try {
|
|
943
|
+
this.config = JSON.parse(this.initialJson);
|
|
944
|
+
this.tokensError = '';
|
|
945
|
+
this.isValid$.next(true);
|
|
946
|
+
this.isDirty$.next(false);
|
|
947
|
+
}
|
|
948
|
+
catch { }
|
|
949
|
+
}
|
|
950
|
+
stringifyTokens(tokens) {
|
|
951
|
+
if (!tokens || Object.keys(tokens).length === 0)
|
|
952
|
+
return '';
|
|
953
|
+
try {
|
|
954
|
+
return JSON.stringify(tokens, null, 2);
|
|
955
|
+
}
|
|
956
|
+
catch {
|
|
957
|
+
return '';
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
setAppearance(key, value) {
|
|
961
|
+
const ap = { ...(this.config?.appearance || {}) };
|
|
962
|
+
if (value === '' || value === null || typeof value === 'undefined') {
|
|
963
|
+
delete ap[key];
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
ap[key] = value;
|
|
967
|
+
}
|
|
968
|
+
this.setConfig({ ...(this.config || {}), appearance: ap });
|
|
969
|
+
}
|
|
970
|
+
setTokens(text) {
|
|
971
|
+
const raw = (text || '').trim();
|
|
972
|
+
if (!raw) {
|
|
973
|
+
this.tokensError = '';
|
|
974
|
+
this.setAppearance('tokens', undefined);
|
|
975
|
+
this.isValid$.next(true);
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
try {
|
|
979
|
+
const parsed = JSON.parse(raw);
|
|
980
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
981
|
+
this.tokensError = 'Formato inválido: use um objeto JSON.';
|
|
982
|
+
this.isValid$.next(false);
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
this.tokensError = '';
|
|
986
|
+
this.isValid$.next(true);
|
|
987
|
+
this.setAppearance('tokens', parsed);
|
|
988
|
+
}
|
|
989
|
+
catch (err) {
|
|
990
|
+
this.tokensError = err?.message || 'JSON inválido.';
|
|
991
|
+
this.isValid$.next(false);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
setContainer(key, value) {
|
|
995
|
+
const container = { ...(this.config?.appearance?.container || {}) };
|
|
996
|
+
if (value === '' || value === null || typeof value === 'undefined') {
|
|
997
|
+
delete container[key];
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
container[key] = value;
|
|
1001
|
+
}
|
|
1002
|
+
const next = Object.keys(container).length ? container : undefined;
|
|
1003
|
+
this.setAppearance('container', next);
|
|
1004
|
+
}
|
|
1005
|
+
setHeader(key, value) {
|
|
1006
|
+
const header = { ...(this.config?.appearance?.header || {}) };
|
|
1007
|
+
if (value === '' || value === null || typeof value === 'undefined') {
|
|
1008
|
+
delete header[key];
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
header[key] = value;
|
|
1012
|
+
}
|
|
1013
|
+
const next = Object.keys(header).length ? header : undefined;
|
|
1014
|
+
this.setAppearance('header', next);
|
|
1015
|
+
}
|
|
1016
|
+
setState(state, key, value) {
|
|
1017
|
+
const current = { ...(this.config?.appearance?.states || {}) };
|
|
1018
|
+
const stateObj = { ...(current[state] || {}) };
|
|
1019
|
+
if (value === '' || value === null || typeof value === 'undefined') {
|
|
1020
|
+
delete stateObj[key];
|
|
1021
|
+
}
|
|
1022
|
+
else {
|
|
1023
|
+
stateObj[key] = value;
|
|
1024
|
+
}
|
|
1025
|
+
if (Object.keys(stateObj).length) {
|
|
1026
|
+
current[state] = stateObj;
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
delete current[state];
|
|
1030
|
+
}
|
|
1031
|
+
const next = Object.keys(current).length ? current : undefined;
|
|
1032
|
+
this.setAppearance('states', next);
|
|
1033
|
+
}
|
|
451
1034
|
addPanel() {
|
|
452
1035
|
const next = { ...(this.config || {}), panels: [...(this.config?.panels || []), { title: 'Novo painel' }] };
|
|
453
|
-
this.
|
|
1036
|
+
this.setConfig(next);
|
|
454
1037
|
}
|
|
455
1038
|
removePanel(index) {
|
|
456
1039
|
if (!this.config?.panels)
|
|
457
1040
|
return;
|
|
458
1041
|
const next = { ...this.config, panels: this.config.panels.filter((_, i) => i !== index) };
|
|
459
|
-
this.
|
|
1042
|
+
this.setConfig(next);
|
|
460
1043
|
}
|
|
461
1044
|
move(index, delta) {
|
|
462
1045
|
if (!this.config?.panels)
|
|
@@ -467,48 +1050,241 @@ class PraxisExpansionConfigEditor {
|
|
|
467
1050
|
return;
|
|
468
1051
|
const [m] = arr.splice(index, 1);
|
|
469
1052
|
arr.splice(to, 0, m);
|
|
470
|
-
this.
|
|
1053
|
+
this.setConfig({ ...(this.config || {}), panels: arr });
|
|
471
1054
|
}
|
|
472
1055
|
setAccordion(key, value) {
|
|
473
1056
|
const acc = { ...(this.config?.accordion || {}) };
|
|
474
1057
|
acc[key] = value;
|
|
475
|
-
this.
|
|
1058
|
+
this.setConfig({ ...(this.config || {}), accordion: acc });
|
|
476
1059
|
}
|
|
477
1060
|
setPanel(index, key, value) {
|
|
478
1061
|
if (!this.config?.panels)
|
|
479
1062
|
return;
|
|
480
1063
|
const arr = this.config.panels.map((p, i) => i === index ? { ...p, [key]: value } : p);
|
|
481
|
-
this.
|
|
1064
|
+
this.setConfig({ ...(this.config || {}), panels: arr });
|
|
1065
|
+
}
|
|
1066
|
+
setConfig(next) {
|
|
1067
|
+
this.config = next;
|
|
1068
|
+
if (!this.hasInitializedSnapshot) {
|
|
1069
|
+
this.captureInitialSnapshot(next);
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
this.updateDirtyState();
|
|
482
1073
|
}
|
|
483
|
-
|
|
484
|
-
|
|
1074
|
+
captureInitialSnapshot(cfg) {
|
|
1075
|
+
this.initialJson = JSON.stringify(cfg || {});
|
|
1076
|
+
this.hasInitializedSnapshot = true;
|
|
1077
|
+
this.isDirty$.next(false);
|
|
1078
|
+
}
|
|
1079
|
+
updateDirtyState() {
|
|
1080
|
+
if (!this.hasInitializedSnapshot)
|
|
1081
|
+
return;
|
|
1082
|
+
const current = JSON.stringify(this.config || {});
|
|
1083
|
+
this.isDirty$.next(current !== this.initialJson);
|
|
1084
|
+
}
|
|
1085
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisExpansionConfigEditor, deps: [{ token: SETTINGS_PANEL_DATA }], target: i0.ɵɵFactoryTarget.Component });
|
|
1086
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisExpansionConfigEditor, isStandalone: true, selector: "praxis-expansion-config-editor", inputs: { config: "config", expansionId: "expansionId" }, usesOnChanges: true, ngImport: i0, template: `
|
|
485
1087
|
<div class="pdx-expansion-editor">
|
|
486
1088
|
<section class="sec">
|
|
487
|
-
<h4>
|
|
488
|
-
<div class="grid">
|
|
489
|
-
<
|
|
490
|
-
<
|
|
491
|
-
<input
|
|
492
|
-
</
|
|
493
|
-
<
|
|
494
|
-
<
|
|
495
|
-
<select [value]="config?.
|
|
496
|
-
<option value="
|
|
497
|
-
<option value="
|
|
1089
|
+
<h4>Aparência</h4>
|
|
1090
|
+
<div class="grid two">
|
|
1091
|
+
<mat-form-field appearance="outline">
|
|
1092
|
+
<mat-label>Classe de tema</mat-label>
|
|
1093
|
+
<input matInput [value]="config?.appearance?.themeClass || ''" (input)="setAppearance('themeClass', $any($event.target).value)" placeholder="ex.: expansion-accent" />
|
|
1094
|
+
</mat-form-field>
|
|
1095
|
+
<mat-form-field appearance="outline">
|
|
1096
|
+
<mat-label>Densidade</mat-label>
|
|
1097
|
+
<select matNativeControl [value]="config?.appearance?.density || ''" (change)="setAppearance('density', $any($event.target).value || undefined)">
|
|
1098
|
+
<option value="">Padrão</option>
|
|
1099
|
+
<option value="compact">Compacta</option>
|
|
1100
|
+
<option value="comfortable">Confortável</option>
|
|
1101
|
+
<option value="spacious">Espaçosa</option>
|
|
498
1102
|
</select>
|
|
499
|
-
</
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
1103
|
+
</mat-form-field>
|
|
1104
|
+
</div>
|
|
1105
|
+
|
|
1106
|
+
<h5>Container</h5>
|
|
1107
|
+
<div class="grid two">
|
|
1108
|
+
<mat-form-field appearance="outline">
|
|
1109
|
+
<mat-label>Background</mat-label>
|
|
1110
|
+
<input matInput [value]="config?.appearance?.container?.background || ''" (input)="setContainer('background', $any($event.target).value)" placeholder="var(--md-sys-color-surface)" />
|
|
1111
|
+
</mat-form-field>
|
|
1112
|
+
<mat-form-field appearance="outline">
|
|
1113
|
+
<mat-label>Padding</mat-label>
|
|
1114
|
+
<input matInput [value]="config?.appearance?.container?.padding || ''" (input)="setContainer('padding', $any($event.target).value)" placeholder="0" />
|
|
1115
|
+
</mat-form-field>
|
|
1116
|
+
<mat-form-field appearance="outline">
|
|
1117
|
+
<mat-label>Cor da borda</mat-label>
|
|
1118
|
+
<input matInput [value]="config?.appearance?.container?.borderColor || ''" (input)="setContainer('borderColor', $any($event.target).value)" placeholder="var(--md-sys-color-outline-variant)" />
|
|
1119
|
+
</mat-form-field>
|
|
1120
|
+
<mat-form-field appearance="outline">
|
|
1121
|
+
<mat-label>Espessura da borda</mat-label>
|
|
1122
|
+
<input matInput [value]="config?.appearance?.container?.borderWidth || ''" (input)="setContainer('borderWidth', $any($event.target).value)" placeholder="1px" />
|
|
1123
|
+
</mat-form-field>
|
|
1124
|
+
<mat-form-field appearance="outline">
|
|
1125
|
+
<mat-label>Estilo da borda</mat-label>
|
|
1126
|
+
<select matNativeControl [value]="config?.appearance?.container?.borderStyle || ''" (change)="setContainer('borderStyle', $any($event.target).value || undefined)">
|
|
1127
|
+
<option value="">Padrão</option>
|
|
1128
|
+
<option value="solid">Solid</option>
|
|
1129
|
+
<option value="dashed">Dashed</option>
|
|
1130
|
+
<option value="dotted">Dotted</option>
|
|
1131
|
+
<option value="none">None</option>
|
|
505
1132
|
</select>
|
|
506
|
-
</
|
|
507
|
-
<
|
|
508
|
-
|
|
1133
|
+
</mat-form-field>
|
|
1134
|
+
<mat-form-field appearance="outline">
|
|
1135
|
+
<mat-label>Raio da borda</mat-label>
|
|
1136
|
+
<input matInput [value]="config?.appearance?.container?.borderRadius || ''" (input)="setContainer('borderRadius', $any($event.target).value)" placeholder="12px" />
|
|
1137
|
+
</mat-form-field>
|
|
1138
|
+
<mat-form-field appearance="outline">
|
|
1139
|
+
<mat-label>Sombra</mat-label>
|
|
1140
|
+
<input matInput [value]="config?.appearance?.container?.shadow || ''" (input)="setContainer('shadow', $any($event.target).value)" placeholder="var(--md-sys-color-shadow)" />
|
|
1141
|
+
</mat-form-field>
|
|
1142
|
+
<mat-form-field appearance="outline">
|
|
1143
|
+
<mat-label>Espaço entre painéis</mat-label>
|
|
1144
|
+
<input matInput [value]="config?.appearance?.container?.panelGap || ''" (input)="setContainer('panelGap', $any($event.target).value)" placeholder="12px" />
|
|
1145
|
+
</mat-form-field>
|
|
1146
|
+
</div>
|
|
1147
|
+
|
|
1148
|
+
<h5>Cabeçalho</h5>
|
|
1149
|
+
<div class="grid two">
|
|
1150
|
+
<mat-form-field appearance="outline">
|
|
1151
|
+
<mat-label>Background</mat-label>
|
|
1152
|
+
<input matInput [value]="config?.appearance?.header?.background || ''" (input)="setHeader('background', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container)" />
|
|
1153
|
+
</mat-form-field>
|
|
1154
|
+
<mat-form-field appearance="outline">
|
|
1155
|
+
<mat-label>Cor do texto</mat-label>
|
|
1156
|
+
<input matInput [value]="config?.appearance?.header?.textColor || ''" (input)="setHeader('textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1157
|
+
</mat-form-field>
|
|
1158
|
+
<mat-form-field appearance="outline">
|
|
1159
|
+
<mat-label>Cor do título</mat-label>
|
|
1160
|
+
<input matInput [value]="config?.appearance?.header?.titleColor || ''" (input)="setHeader('titleColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1161
|
+
</mat-form-field>
|
|
1162
|
+
<mat-form-field appearance="outline">
|
|
1163
|
+
<mat-label>Cor da descrição</mat-label>
|
|
1164
|
+
<input matInput [value]="config?.appearance?.header?.descriptionColor || ''" (input)="setHeader('descriptionColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface-variant)" />
|
|
1165
|
+
</mat-form-field>
|
|
1166
|
+
<mat-form-field appearance="outline">
|
|
1167
|
+
<mat-label>Altura</mat-label>
|
|
1168
|
+
<input matInput [value]="config?.appearance?.header?.height || ''" (input)="setHeader('height', $any($event.target).value)" placeholder="48px" />
|
|
1169
|
+
</mat-form-field>
|
|
1170
|
+
<mat-form-field appearance="outline">
|
|
1171
|
+
<mat-label>Padding</mat-label>
|
|
1172
|
+
<input matInput [value]="config?.appearance?.header?.padding || ''" (input)="setHeader('padding', $any($event.target).value)" placeholder="0 16px" />
|
|
1173
|
+
</mat-form-field>
|
|
1174
|
+
<mat-form-field appearance="outline">
|
|
1175
|
+
<mat-label>Gap</mat-label>
|
|
1176
|
+
<input matInput [value]="config?.appearance?.header?.gap || ''" (input)="setHeader('gap', $any($event.target).value)" placeholder="12px" />
|
|
1177
|
+
</mat-form-field>
|
|
1178
|
+
<mat-form-field appearance="outline">
|
|
1179
|
+
<mat-label>Font family</mat-label>
|
|
1180
|
+
<input matInput [value]="config?.appearance?.header?.fontFamily || ''" (input)="setHeader('fontFamily', $any($event.target).value)" placeholder="inherit" />
|
|
1181
|
+
</mat-form-field>
|
|
1182
|
+
<mat-form-field appearance="outline">
|
|
1183
|
+
<mat-label>Tamanho do título</mat-label>
|
|
1184
|
+
<input matInput [value]="config?.appearance?.header?.titleSize || ''" (input)="setHeader('titleSize', $any($event.target).value)" placeholder="14px" />
|
|
1185
|
+
</mat-form-field>
|
|
1186
|
+
<mat-form-field appearance="outline">
|
|
1187
|
+
<mat-label>Peso do título</mat-label>
|
|
1188
|
+
<input matInput [value]="config?.appearance?.header?.titleWeight || ''" (input)="setHeader('titleWeight', $any($event.target).value)" placeholder="600" />
|
|
1189
|
+
</mat-form-field>
|
|
1190
|
+
<mat-form-field appearance="outline">
|
|
1191
|
+
<mat-label>Tamanho da descrição</mat-label>
|
|
1192
|
+
<input matInput [value]="config?.appearance?.header?.descriptionSize || ''" (input)="setHeader('descriptionSize', $any($event.target).value)" placeholder="12px" />
|
|
1193
|
+
</mat-form-field>
|
|
1194
|
+
<mat-form-field appearance="outline">
|
|
1195
|
+
<mat-label>Peso da descrição</mat-label>
|
|
1196
|
+
<input matInput [value]="config?.appearance?.header?.descriptionWeight || ''" (input)="setHeader('descriptionWeight', $any($event.target).value)" placeholder="400" />
|
|
1197
|
+
</mat-form-field>
|
|
1198
|
+
<mat-form-field appearance="outline">
|
|
1199
|
+
<mat-label>Cor do ícone toggle</mat-label>
|
|
1200
|
+
<input matInput [value]="config?.appearance?.header?.toggleIconColor || ''" (input)="setHeader('toggleIconColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface-variant)" />
|
|
1201
|
+
</mat-form-field>
|
|
1202
|
+
<mat-form-field appearance="outline">
|
|
1203
|
+
<mat-label>Tamanho do ícone toggle</mat-label>
|
|
1204
|
+
<input matInput [value]="config?.appearance?.header?.toggleIconSize || ''" (input)="setHeader('toggleIconSize', $any($event.target).value)" placeholder="12px" />
|
|
1205
|
+
</mat-form-field>
|
|
1206
|
+
</div>
|
|
1207
|
+
|
|
1208
|
+
<h5>Estados</h5>
|
|
1209
|
+
<div class="grid two">
|
|
1210
|
+
<mat-form-field appearance="outline">
|
|
1211
|
+
<mat-label>Hover - background</mat-label>
|
|
1212
|
+
<input matInput [value]="config?.appearance?.states?.hover?.headerBackground || ''" (input)="setState('hover', 'headerBackground', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container-high)" />
|
|
1213
|
+
</mat-form-field>
|
|
1214
|
+
<mat-form-field appearance="outline">
|
|
1215
|
+
<mat-label>Hover - texto</mat-label>
|
|
1216
|
+
<input matInput [value]="config?.appearance?.states?.hover?.textColor || ''" (input)="setState('hover', 'textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1217
|
+
</mat-form-field>
|
|
1218
|
+
<mat-form-field appearance="outline">
|
|
1219
|
+
<mat-label>Expandido - background</mat-label>
|
|
1220
|
+
<input matInput [value]="config?.appearance?.states?.expanded?.headerBackground || ''" (input)="setState('expanded', 'headerBackground', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container)" />
|
|
1221
|
+
</mat-form-field>
|
|
1222
|
+
<mat-form-field appearance="outline">
|
|
1223
|
+
<mat-label>Expandido - texto</mat-label>
|
|
1224
|
+
<input matInput [value]="config?.appearance?.states?.expanded?.textColor || ''" (input)="setState('expanded', 'textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1225
|
+
</mat-form-field>
|
|
1226
|
+
<mat-form-field appearance="outline">
|
|
1227
|
+
<mat-label>Expandido - accent bar</mat-label>
|
|
1228
|
+
<input matInput [value]="config?.appearance?.states?.expanded?.accentBarColor || ''" (input)="setState('expanded', 'accentBarColor', $any($event.target).value)" placeholder="var(--md-sys-color-primary)" />
|
|
1229
|
+
</mat-form-field>
|
|
1230
|
+
<mat-form-field appearance="outline">
|
|
1231
|
+
<mat-label>Desabilitado - background</mat-label>
|
|
1232
|
+
<input matInput [value]="config?.appearance?.states?.disabled?.headerBackground || ''" (input)="setState('disabled', 'headerBackground', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container)" />
|
|
1233
|
+
</mat-form-field>
|
|
1234
|
+
<mat-form-field appearance="outline">
|
|
1235
|
+
<mat-label>Desabilitado - texto</mat-label>
|
|
1236
|
+
<input matInput [value]="config?.appearance?.states?.disabled?.textColor || ''" (input)="setState('disabled', 'textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface-variant)" />
|
|
1237
|
+
</mat-form-field>
|
|
1238
|
+
</div>
|
|
1239
|
+
<mat-form-field appearance="outline" class="full">
|
|
1240
|
+
<mat-label>CSS personalizado</mat-label>
|
|
1241
|
+
<textarea matInput rows="4" [value]="config?.appearance?.customCss || ''" (input)="setAppearance('customCss', $any($event.target).value)" placeholder=".praxis-expansion-root .mat-expansion-panel { }"></textarea>
|
|
1242
|
+
</mat-form-field>
|
|
1243
|
+
<mat-form-field appearance="outline" class="full">
|
|
1244
|
+
<mat-label>Tokens (JSON)</mat-label>
|
|
1245
|
+
<textarea matInput rows="4" [value]="stringifyTokens(config?.appearance?.tokens)" (input)="setTokens($any($event.target).value)" placeholder='{"header-background-color":"var(--md-sys-color-surface-container)"}'></textarea>
|
|
1246
|
+
<button
|
|
1247
|
+
mat-icon-button
|
|
1248
|
+
matSuffix
|
|
1249
|
+
class="help-icon-button"
|
|
1250
|
+
type="button"
|
|
1251
|
+
[matTooltip]="'Use tokens M3, por exemplo: var(--md-sys-color-primary)'"
|
|
1252
|
+
matTooltipPosition="above"
|
|
1253
|
+
>
|
|
1254
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1255
|
+
</button>
|
|
1256
|
+
</mat-form-field>
|
|
1257
|
+
<div class="error" *ngIf="tokensError">{{ tokensError }}</div>
|
|
1258
|
+
</section>
|
|
1259
|
+
|
|
1260
|
+
<section class="sec">
|
|
1261
|
+
<h4>Configuração do acordeão</h4>
|
|
1262
|
+
<div class="grid two">
|
|
1263
|
+
<mat-form-field appearance="outline">
|
|
1264
|
+
<mat-label>ID</mat-label>
|
|
1265
|
+
<input matInput [value]="config?.accordion?.id || ''" (input)="setAccordion('id', $any($event.target).value)" />
|
|
1266
|
+
</mat-form-field>
|
|
1267
|
+
<mat-form-field appearance="outline">
|
|
1268
|
+
<mat-label>Modo de exibição</mat-label>
|
|
1269
|
+
<select matNativeControl [value]="config?.accordion?.displayMode || 'default'" (change)="setAccordion('displayMode', $any($event.target).value)">
|
|
1270
|
+
<option value="default">Padrão</option>
|
|
1271
|
+
<option value="flat">Flat</option>
|
|
1272
|
+
</select>
|
|
1273
|
+
</mat-form-field>
|
|
1274
|
+
<mat-form-field appearance="outline">
|
|
1275
|
+
<mat-label>Posição do toggle</mat-label>
|
|
1276
|
+
<select matNativeControl [value]="config?.accordion?.togglePosition || 'after'" (change)="setAccordion('togglePosition', $any($event.target).value)">
|
|
1277
|
+
<option value="after">Depois</option>
|
|
1278
|
+
<option value="before">Antes</option>
|
|
1279
|
+
</select>
|
|
1280
|
+
</mat-form-field>
|
|
1281
|
+
<div class="row wrap">
|
|
1282
|
+
<mat-slide-toggle [checked]="config?.accordion?.multi || false" (change)="setAccordion('multi', $event.checked)">Múltiplos abertos</mat-slide-toggle>
|
|
1283
|
+
<mat-slide-toggle [checked]="config?.accordion?.hideToggle || false" (change)="setAccordion('hideToggle', $event.checked)">Ocultar toggle</mat-slide-toggle>
|
|
1284
|
+
</div>
|
|
509
1285
|
</div>
|
|
510
1286
|
<div class="row">
|
|
511
|
-
<button mat-stroked-button color="primary" (click)="addPanel()"><mat-icon [praxisIcon]="'add'"></mat-icon>
|
|
1287
|
+
<button mat-stroked-button color="primary" (click)="addPanel()"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar painel</button>
|
|
512
1288
|
</div>
|
|
513
1289
|
</section>
|
|
514
1290
|
|
|
@@ -516,54 +1292,249 @@ class PraxisExpansionConfigEditor {
|
|
|
516
1292
|
<div class="panel-row">
|
|
517
1293
|
<strong>{{ p.title || ('Painel ' + (i + 1)) }}</strong>
|
|
518
1294
|
<span class="grow"></span>
|
|
519
|
-
<button mat-button (click)="move(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon>
|
|
520
|
-
<button mat-button (click)="move(i, 1)" [disabled]="i>=(config!.panels!.length-1)"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon>
|
|
521
|
-
<button mat-button color="warn" (click)="removePanel(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon>
|
|
1295
|
+
<button mat-button (click)="move(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon>Subir</button>
|
|
1296
|
+
<button mat-button (click)="move(i, 1)" [disabled]="i>=(config!.panels!.length-1)"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon>Descer</button>
|
|
1297
|
+
<button mat-button color="warn" (click)="removePanel(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon>Remover</button>
|
|
522
1298
|
</div>
|
|
523
|
-
<div class="grid">
|
|
524
|
-
<
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
<
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
<
|
|
531
|
-
|
|
1299
|
+
<div class="grid two">
|
|
1300
|
+
<mat-form-field appearance="outline"><mat-label>ID</mat-label>
|
|
1301
|
+
<input matInput [value]="p.id || ''" (input)="setPanel(i, 'id', $any($event.target).value)" />
|
|
1302
|
+
</mat-form-field>
|
|
1303
|
+
<mat-form-field appearance="outline"><mat-label>Título</mat-label>
|
|
1304
|
+
<input matInput [value]="p.title || ''" (input)="setPanel(i, 'title', $any($event.target).value)" />
|
|
1305
|
+
</mat-form-field>
|
|
1306
|
+
<mat-form-field appearance="outline"><mat-label>Descrição</mat-label>
|
|
1307
|
+
<input matInput [value]="p.description || ''" (input)="setPanel(i, 'description', $any($event.target).value)" />
|
|
1308
|
+
</mat-form-field>
|
|
1309
|
+
<mat-form-field appearance="outline"><mat-label>Altura recolhida</mat-label>
|
|
1310
|
+
<input matInput placeholder="48px" [value]="p.collapsedHeight || ''" (input)="setPanel(i, 'collapsedHeight', $any($event.target).value)" />
|
|
1311
|
+
</mat-form-field>
|
|
1312
|
+
<mat-form-field appearance="outline"><mat-label>Altura expandida</mat-label>
|
|
1313
|
+
<input matInput placeholder="64px" [value]="p.expandedHeight || ''" (input)="setPanel(i, 'expandedHeight', $any($event.target).value)" />
|
|
1314
|
+
</mat-form-field>
|
|
1315
|
+
<div class="row wrap">
|
|
1316
|
+
<mat-slide-toggle [checked]="p.disabled || false" (change)="setPanel(i, 'disabled', $event.checked)">Desativado</mat-slide-toggle>
|
|
1317
|
+
<mat-slide-toggle [checked]="p.expanded || false" (change)="setPanel(i, 'expanded', $event.checked)">Expandido</mat-slide-toggle>
|
|
1318
|
+
<mat-slide-toggle [checked]="p.hideToggle || false" (change)="setPanel(i, 'hideToggle', $event.checked)">Ocultar toggle</mat-slide-toggle>
|
|
1319
|
+
</div>
|
|
532
1320
|
</div>
|
|
533
1321
|
</section>
|
|
534
1322
|
</div>
|
|
535
|
-
`, isInline: true, styles: [".pdx-expansion-editor{display:grid;gap:16px}.sec{border:1px
|
|
1323
|
+
`, isInline: true, styles: [":host{display:block;color:var(--md-sys-color-on-surface)}.pdx-expansion-editor{display:grid;gap:16px}.sec{border:1px solid var(--md-sys-color-outline-variant);padding:12px;border-radius:10px;background:var(--md-sys-color-surface-container-lowest);display:grid;gap:12px}.row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.row.wrap{flex-wrap:wrap}.panel-row{display:flex;gap:8px;align-items:center;width:100%}.grow{flex:1 1 auto}.grid{display:grid;gap:10px;align-items:center}.grid.two{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.full{width:100%}.error{color:var(--md-sys-color-error);font-size:12px}.pdx-expansion-editor .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
536
1324
|
}
|
|
537
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
1325
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisExpansionConfigEditor, decorators: [{
|
|
538
1326
|
type: Component,
|
|
539
|
-
args: [{ selector: 'praxis-expansion-config-editor', standalone: true, imports: [
|
|
1327
|
+
args: [{ selector: 'praxis-expansion-config-editor', standalone: true, imports: [
|
|
1328
|
+
CommonModule,
|
|
1329
|
+
MatButtonModule,
|
|
1330
|
+
MatIconModule,
|
|
1331
|
+
MatFormFieldModule,
|
|
1332
|
+
MatInputModule,
|
|
1333
|
+
MatSlideToggleModule,
|
|
1334
|
+
MatTooltipModule,
|
|
1335
|
+
PraxisIconDirective,
|
|
1336
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
540
1337
|
<div class="pdx-expansion-editor">
|
|
541
1338
|
<section class="sec">
|
|
542
|
-
<h4>
|
|
543
|
-
<div class="grid">
|
|
544
|
-
<
|
|
545
|
-
<
|
|
546
|
-
<input
|
|
547
|
-
</
|
|
548
|
-
<
|
|
549
|
-
<
|
|
550
|
-
<select [value]="config?.
|
|
551
|
-
<option value="
|
|
552
|
-
<option value="
|
|
1339
|
+
<h4>Aparência</h4>
|
|
1340
|
+
<div class="grid two">
|
|
1341
|
+
<mat-form-field appearance="outline">
|
|
1342
|
+
<mat-label>Classe de tema</mat-label>
|
|
1343
|
+
<input matInput [value]="config?.appearance?.themeClass || ''" (input)="setAppearance('themeClass', $any($event.target).value)" placeholder="ex.: expansion-accent" />
|
|
1344
|
+
</mat-form-field>
|
|
1345
|
+
<mat-form-field appearance="outline">
|
|
1346
|
+
<mat-label>Densidade</mat-label>
|
|
1347
|
+
<select matNativeControl [value]="config?.appearance?.density || ''" (change)="setAppearance('density', $any($event.target).value || undefined)">
|
|
1348
|
+
<option value="">Padrão</option>
|
|
1349
|
+
<option value="compact">Compacta</option>
|
|
1350
|
+
<option value="comfortable">Confortável</option>
|
|
1351
|
+
<option value="spacious">Espaçosa</option>
|
|
553
1352
|
</select>
|
|
554
|
-
</
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
1353
|
+
</mat-form-field>
|
|
1354
|
+
</div>
|
|
1355
|
+
|
|
1356
|
+
<h5>Container</h5>
|
|
1357
|
+
<div class="grid two">
|
|
1358
|
+
<mat-form-field appearance="outline">
|
|
1359
|
+
<mat-label>Background</mat-label>
|
|
1360
|
+
<input matInput [value]="config?.appearance?.container?.background || ''" (input)="setContainer('background', $any($event.target).value)" placeholder="var(--md-sys-color-surface)" />
|
|
1361
|
+
</mat-form-field>
|
|
1362
|
+
<mat-form-field appearance="outline">
|
|
1363
|
+
<mat-label>Padding</mat-label>
|
|
1364
|
+
<input matInput [value]="config?.appearance?.container?.padding || ''" (input)="setContainer('padding', $any($event.target).value)" placeholder="0" />
|
|
1365
|
+
</mat-form-field>
|
|
1366
|
+
<mat-form-field appearance="outline">
|
|
1367
|
+
<mat-label>Cor da borda</mat-label>
|
|
1368
|
+
<input matInput [value]="config?.appearance?.container?.borderColor || ''" (input)="setContainer('borderColor', $any($event.target).value)" placeholder="var(--md-sys-color-outline-variant)" />
|
|
1369
|
+
</mat-form-field>
|
|
1370
|
+
<mat-form-field appearance="outline">
|
|
1371
|
+
<mat-label>Espessura da borda</mat-label>
|
|
1372
|
+
<input matInput [value]="config?.appearance?.container?.borderWidth || ''" (input)="setContainer('borderWidth', $any($event.target).value)" placeholder="1px" />
|
|
1373
|
+
</mat-form-field>
|
|
1374
|
+
<mat-form-field appearance="outline">
|
|
1375
|
+
<mat-label>Estilo da borda</mat-label>
|
|
1376
|
+
<select matNativeControl [value]="config?.appearance?.container?.borderStyle || ''" (change)="setContainer('borderStyle', $any($event.target).value || undefined)">
|
|
1377
|
+
<option value="">Padrão</option>
|
|
1378
|
+
<option value="solid">Solid</option>
|
|
1379
|
+
<option value="dashed">Dashed</option>
|
|
1380
|
+
<option value="dotted">Dotted</option>
|
|
1381
|
+
<option value="none">None</option>
|
|
560
1382
|
</select>
|
|
561
|
-
</
|
|
562
|
-
<
|
|
563
|
-
|
|
1383
|
+
</mat-form-field>
|
|
1384
|
+
<mat-form-field appearance="outline">
|
|
1385
|
+
<mat-label>Raio da borda</mat-label>
|
|
1386
|
+
<input matInput [value]="config?.appearance?.container?.borderRadius || ''" (input)="setContainer('borderRadius', $any($event.target).value)" placeholder="12px" />
|
|
1387
|
+
</mat-form-field>
|
|
1388
|
+
<mat-form-field appearance="outline">
|
|
1389
|
+
<mat-label>Sombra</mat-label>
|
|
1390
|
+
<input matInput [value]="config?.appearance?.container?.shadow || ''" (input)="setContainer('shadow', $any($event.target).value)" placeholder="var(--md-sys-color-shadow)" />
|
|
1391
|
+
</mat-form-field>
|
|
1392
|
+
<mat-form-field appearance="outline">
|
|
1393
|
+
<mat-label>Espaço entre painéis</mat-label>
|
|
1394
|
+
<input matInput [value]="config?.appearance?.container?.panelGap || ''" (input)="setContainer('panelGap', $any($event.target).value)" placeholder="12px" />
|
|
1395
|
+
</mat-form-field>
|
|
1396
|
+
</div>
|
|
1397
|
+
|
|
1398
|
+
<h5>Cabeçalho</h5>
|
|
1399
|
+
<div class="grid two">
|
|
1400
|
+
<mat-form-field appearance="outline">
|
|
1401
|
+
<mat-label>Background</mat-label>
|
|
1402
|
+
<input matInput [value]="config?.appearance?.header?.background || ''" (input)="setHeader('background', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container)" />
|
|
1403
|
+
</mat-form-field>
|
|
1404
|
+
<mat-form-field appearance="outline">
|
|
1405
|
+
<mat-label>Cor do texto</mat-label>
|
|
1406
|
+
<input matInput [value]="config?.appearance?.header?.textColor || ''" (input)="setHeader('textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1407
|
+
</mat-form-field>
|
|
1408
|
+
<mat-form-field appearance="outline">
|
|
1409
|
+
<mat-label>Cor do título</mat-label>
|
|
1410
|
+
<input matInput [value]="config?.appearance?.header?.titleColor || ''" (input)="setHeader('titleColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1411
|
+
</mat-form-field>
|
|
1412
|
+
<mat-form-field appearance="outline">
|
|
1413
|
+
<mat-label>Cor da descrição</mat-label>
|
|
1414
|
+
<input matInput [value]="config?.appearance?.header?.descriptionColor || ''" (input)="setHeader('descriptionColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface-variant)" />
|
|
1415
|
+
</mat-form-field>
|
|
1416
|
+
<mat-form-field appearance="outline">
|
|
1417
|
+
<mat-label>Altura</mat-label>
|
|
1418
|
+
<input matInput [value]="config?.appearance?.header?.height || ''" (input)="setHeader('height', $any($event.target).value)" placeholder="48px" />
|
|
1419
|
+
</mat-form-field>
|
|
1420
|
+
<mat-form-field appearance="outline">
|
|
1421
|
+
<mat-label>Padding</mat-label>
|
|
1422
|
+
<input matInput [value]="config?.appearance?.header?.padding || ''" (input)="setHeader('padding', $any($event.target).value)" placeholder="0 16px" />
|
|
1423
|
+
</mat-form-field>
|
|
1424
|
+
<mat-form-field appearance="outline">
|
|
1425
|
+
<mat-label>Gap</mat-label>
|
|
1426
|
+
<input matInput [value]="config?.appearance?.header?.gap || ''" (input)="setHeader('gap', $any($event.target).value)" placeholder="12px" />
|
|
1427
|
+
</mat-form-field>
|
|
1428
|
+
<mat-form-field appearance="outline">
|
|
1429
|
+
<mat-label>Font family</mat-label>
|
|
1430
|
+
<input matInput [value]="config?.appearance?.header?.fontFamily || ''" (input)="setHeader('fontFamily', $any($event.target).value)" placeholder="inherit" />
|
|
1431
|
+
</mat-form-field>
|
|
1432
|
+
<mat-form-field appearance="outline">
|
|
1433
|
+
<mat-label>Tamanho do título</mat-label>
|
|
1434
|
+
<input matInput [value]="config?.appearance?.header?.titleSize || ''" (input)="setHeader('titleSize', $any($event.target).value)" placeholder="14px" />
|
|
1435
|
+
</mat-form-field>
|
|
1436
|
+
<mat-form-field appearance="outline">
|
|
1437
|
+
<mat-label>Peso do título</mat-label>
|
|
1438
|
+
<input matInput [value]="config?.appearance?.header?.titleWeight || ''" (input)="setHeader('titleWeight', $any($event.target).value)" placeholder="600" />
|
|
1439
|
+
</mat-form-field>
|
|
1440
|
+
<mat-form-field appearance="outline">
|
|
1441
|
+
<mat-label>Tamanho da descrição</mat-label>
|
|
1442
|
+
<input matInput [value]="config?.appearance?.header?.descriptionSize || ''" (input)="setHeader('descriptionSize', $any($event.target).value)" placeholder="12px" />
|
|
1443
|
+
</mat-form-field>
|
|
1444
|
+
<mat-form-field appearance="outline">
|
|
1445
|
+
<mat-label>Peso da descrição</mat-label>
|
|
1446
|
+
<input matInput [value]="config?.appearance?.header?.descriptionWeight || ''" (input)="setHeader('descriptionWeight', $any($event.target).value)" placeholder="400" />
|
|
1447
|
+
</mat-form-field>
|
|
1448
|
+
<mat-form-field appearance="outline">
|
|
1449
|
+
<mat-label>Cor do ícone toggle</mat-label>
|
|
1450
|
+
<input matInput [value]="config?.appearance?.header?.toggleIconColor || ''" (input)="setHeader('toggleIconColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface-variant)" />
|
|
1451
|
+
</mat-form-field>
|
|
1452
|
+
<mat-form-field appearance="outline">
|
|
1453
|
+
<mat-label>Tamanho do ícone toggle</mat-label>
|
|
1454
|
+
<input matInput [value]="config?.appearance?.header?.toggleIconSize || ''" (input)="setHeader('toggleIconSize', $any($event.target).value)" placeholder="12px" />
|
|
1455
|
+
</mat-form-field>
|
|
1456
|
+
</div>
|
|
1457
|
+
|
|
1458
|
+
<h5>Estados</h5>
|
|
1459
|
+
<div class="grid two">
|
|
1460
|
+
<mat-form-field appearance="outline">
|
|
1461
|
+
<mat-label>Hover - background</mat-label>
|
|
1462
|
+
<input matInput [value]="config?.appearance?.states?.hover?.headerBackground || ''" (input)="setState('hover', 'headerBackground', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container-high)" />
|
|
1463
|
+
</mat-form-field>
|
|
1464
|
+
<mat-form-field appearance="outline">
|
|
1465
|
+
<mat-label>Hover - texto</mat-label>
|
|
1466
|
+
<input matInput [value]="config?.appearance?.states?.hover?.textColor || ''" (input)="setState('hover', 'textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1467
|
+
</mat-form-field>
|
|
1468
|
+
<mat-form-field appearance="outline">
|
|
1469
|
+
<mat-label>Expandido - background</mat-label>
|
|
1470
|
+
<input matInput [value]="config?.appearance?.states?.expanded?.headerBackground || ''" (input)="setState('expanded', 'headerBackground', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container)" />
|
|
1471
|
+
</mat-form-field>
|
|
1472
|
+
<mat-form-field appearance="outline">
|
|
1473
|
+
<mat-label>Expandido - texto</mat-label>
|
|
1474
|
+
<input matInput [value]="config?.appearance?.states?.expanded?.textColor || ''" (input)="setState('expanded', 'textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface)" />
|
|
1475
|
+
</mat-form-field>
|
|
1476
|
+
<mat-form-field appearance="outline">
|
|
1477
|
+
<mat-label>Expandido - accent bar</mat-label>
|
|
1478
|
+
<input matInput [value]="config?.appearance?.states?.expanded?.accentBarColor || ''" (input)="setState('expanded', 'accentBarColor', $any($event.target).value)" placeholder="var(--md-sys-color-primary)" />
|
|
1479
|
+
</mat-form-field>
|
|
1480
|
+
<mat-form-field appearance="outline">
|
|
1481
|
+
<mat-label>Desabilitado - background</mat-label>
|
|
1482
|
+
<input matInput [value]="config?.appearance?.states?.disabled?.headerBackground || ''" (input)="setState('disabled', 'headerBackground', $any($event.target).value)" placeholder="var(--md-sys-color-surface-container)" />
|
|
1483
|
+
</mat-form-field>
|
|
1484
|
+
<mat-form-field appearance="outline">
|
|
1485
|
+
<mat-label>Desabilitado - texto</mat-label>
|
|
1486
|
+
<input matInput [value]="config?.appearance?.states?.disabled?.textColor || ''" (input)="setState('disabled', 'textColor', $any($event.target).value)" placeholder="var(--md-sys-color-on-surface-variant)" />
|
|
1487
|
+
</mat-form-field>
|
|
1488
|
+
</div>
|
|
1489
|
+
<mat-form-field appearance="outline" class="full">
|
|
1490
|
+
<mat-label>CSS personalizado</mat-label>
|
|
1491
|
+
<textarea matInput rows="4" [value]="config?.appearance?.customCss || ''" (input)="setAppearance('customCss', $any($event.target).value)" placeholder=".praxis-expansion-root .mat-expansion-panel { }"></textarea>
|
|
1492
|
+
</mat-form-field>
|
|
1493
|
+
<mat-form-field appearance="outline" class="full">
|
|
1494
|
+
<mat-label>Tokens (JSON)</mat-label>
|
|
1495
|
+
<textarea matInput rows="4" [value]="stringifyTokens(config?.appearance?.tokens)" (input)="setTokens($any($event.target).value)" placeholder='{"header-background-color":"var(--md-sys-color-surface-container)"}'></textarea>
|
|
1496
|
+
<button
|
|
1497
|
+
mat-icon-button
|
|
1498
|
+
matSuffix
|
|
1499
|
+
class="help-icon-button"
|
|
1500
|
+
type="button"
|
|
1501
|
+
[matTooltip]="'Use tokens M3, por exemplo: var(--md-sys-color-primary)'"
|
|
1502
|
+
matTooltipPosition="above"
|
|
1503
|
+
>
|
|
1504
|
+
<mat-icon [praxisIcon]="'help_outline'"></mat-icon>
|
|
1505
|
+
</button>
|
|
1506
|
+
</mat-form-field>
|
|
1507
|
+
<div class="error" *ngIf="tokensError">{{ tokensError }}</div>
|
|
1508
|
+
</section>
|
|
1509
|
+
|
|
1510
|
+
<section class="sec">
|
|
1511
|
+
<h4>Configuração do acordeão</h4>
|
|
1512
|
+
<div class="grid two">
|
|
1513
|
+
<mat-form-field appearance="outline">
|
|
1514
|
+
<mat-label>ID</mat-label>
|
|
1515
|
+
<input matInput [value]="config?.accordion?.id || ''" (input)="setAccordion('id', $any($event.target).value)" />
|
|
1516
|
+
</mat-form-field>
|
|
1517
|
+
<mat-form-field appearance="outline">
|
|
1518
|
+
<mat-label>Modo de exibição</mat-label>
|
|
1519
|
+
<select matNativeControl [value]="config?.accordion?.displayMode || 'default'" (change)="setAccordion('displayMode', $any($event.target).value)">
|
|
1520
|
+
<option value="default">Padrão</option>
|
|
1521
|
+
<option value="flat">Flat</option>
|
|
1522
|
+
</select>
|
|
1523
|
+
</mat-form-field>
|
|
1524
|
+
<mat-form-field appearance="outline">
|
|
1525
|
+
<mat-label>Posição do toggle</mat-label>
|
|
1526
|
+
<select matNativeControl [value]="config?.accordion?.togglePosition || 'after'" (change)="setAccordion('togglePosition', $any($event.target).value)">
|
|
1527
|
+
<option value="after">Depois</option>
|
|
1528
|
+
<option value="before">Antes</option>
|
|
1529
|
+
</select>
|
|
1530
|
+
</mat-form-field>
|
|
1531
|
+
<div class="row wrap">
|
|
1532
|
+
<mat-slide-toggle [checked]="config?.accordion?.multi || false" (change)="setAccordion('multi', $event.checked)">Múltiplos abertos</mat-slide-toggle>
|
|
1533
|
+
<mat-slide-toggle [checked]="config?.accordion?.hideToggle || false" (change)="setAccordion('hideToggle', $event.checked)">Ocultar toggle</mat-slide-toggle>
|
|
1534
|
+
</div>
|
|
564
1535
|
</div>
|
|
565
1536
|
<div class="row">
|
|
566
|
-
<button mat-stroked-button color="primary" (click)="addPanel()"><mat-icon [praxisIcon]="'add'"></mat-icon>
|
|
1537
|
+
<button mat-stroked-button color="primary" (click)="addPanel()"><mat-icon [praxisIcon]="'add'"></mat-icon>Adicionar painel</button>
|
|
567
1538
|
</div>
|
|
568
1539
|
</section>
|
|
569
1540
|
|
|
@@ -571,24 +1542,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
571
1542
|
<div class="panel-row">
|
|
572
1543
|
<strong>{{ p.title || ('Painel ' + (i + 1)) }}</strong>
|
|
573
1544
|
<span class="grow"></span>
|
|
574
|
-
<button mat-button (click)="move(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon>
|
|
575
|
-
<button mat-button (click)="move(i, 1)" [disabled]="i>=(config!.panels!.length-1)"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon>
|
|
576
|
-
<button mat-button color="warn" (click)="removePanel(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon>
|
|
1545
|
+
<button mat-button (click)="move(i, -1)" [disabled]="i===0"><mat-icon [praxisIcon]="'arrow_upward'"></mat-icon>Subir</button>
|
|
1546
|
+
<button mat-button (click)="move(i, 1)" [disabled]="i>=(config!.panels!.length-1)"><mat-icon [praxisIcon]="'arrow_downward'"></mat-icon>Descer</button>
|
|
1547
|
+
<button mat-button color="warn" (click)="removePanel(i)"><mat-icon [praxisIcon]="'delete'"></mat-icon>Remover</button>
|
|
577
1548
|
</div>
|
|
578
|
-
<div class="grid">
|
|
579
|
-
<
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
<
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
<
|
|
586
|
-
|
|
1549
|
+
<div class="grid two">
|
|
1550
|
+
<mat-form-field appearance="outline"><mat-label>ID</mat-label>
|
|
1551
|
+
<input matInput [value]="p.id || ''" (input)="setPanel(i, 'id', $any($event.target).value)" />
|
|
1552
|
+
</mat-form-field>
|
|
1553
|
+
<mat-form-field appearance="outline"><mat-label>Título</mat-label>
|
|
1554
|
+
<input matInput [value]="p.title || ''" (input)="setPanel(i, 'title', $any($event.target).value)" />
|
|
1555
|
+
</mat-form-field>
|
|
1556
|
+
<mat-form-field appearance="outline"><mat-label>Descrição</mat-label>
|
|
1557
|
+
<input matInput [value]="p.description || ''" (input)="setPanel(i, 'description', $any($event.target).value)" />
|
|
1558
|
+
</mat-form-field>
|
|
1559
|
+
<mat-form-field appearance="outline"><mat-label>Altura recolhida</mat-label>
|
|
1560
|
+
<input matInput placeholder="48px" [value]="p.collapsedHeight || ''" (input)="setPanel(i, 'collapsedHeight', $any($event.target).value)" />
|
|
1561
|
+
</mat-form-field>
|
|
1562
|
+
<mat-form-field appearance="outline"><mat-label>Altura expandida</mat-label>
|
|
1563
|
+
<input matInput placeholder="64px" [value]="p.expandedHeight || ''" (input)="setPanel(i, 'expandedHeight', $any($event.target).value)" />
|
|
1564
|
+
</mat-form-field>
|
|
1565
|
+
<div class="row wrap">
|
|
1566
|
+
<mat-slide-toggle [checked]="p.disabled || false" (change)="setPanel(i, 'disabled', $event.checked)">Desativado</mat-slide-toggle>
|
|
1567
|
+
<mat-slide-toggle [checked]="p.expanded || false" (change)="setPanel(i, 'expanded', $event.checked)">Expandido</mat-slide-toggle>
|
|
1568
|
+
<mat-slide-toggle [checked]="p.hideToggle || false" (change)="setPanel(i, 'hideToggle', $event.checked)">Ocultar toggle</mat-slide-toggle>
|
|
1569
|
+
</div>
|
|
587
1570
|
</div>
|
|
588
1571
|
</section>
|
|
589
1572
|
</div>
|
|
590
|
-
`, styles: [".pdx-expansion-editor{display:grid;gap:16px}.sec{border:1px
|
|
591
|
-
}],
|
|
1573
|
+
`, styles: [":host{display:block;color:var(--md-sys-color-on-surface)}.pdx-expansion-editor{display:grid;gap:16px}.sec{border:1px solid var(--md-sys-color-outline-variant);padding:12px;border-radius:10px;background:var(--md-sys-color-surface-container-lowest);display:grid;gap:12px}.row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.row.wrap{flex-wrap:wrap}.panel-row{display:flex;gap:8px;align-items:center;width:100%}.grow{flex:1 1 auto}.grid{display:grid;gap:10px;align-items:center}.grid.two{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.full{width:100%}.error{color:var(--md-sys-color-error);font-size:12px}.pdx-expansion-editor .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"] }]
|
|
1574
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1575
|
+
type: Inject,
|
|
1576
|
+
args: [SETTINGS_PANEL_DATA]
|
|
1577
|
+
}] }], propDecorators: { config: [{
|
|
592
1578
|
type: Input
|
|
593
1579
|
}], expansionId: [{
|
|
594
1580
|
type: Input
|
|
@@ -599,12 +1585,13 @@ const PRAXIS_EXPANSION_COMPONENT_METADATA = {
|
|
|
599
1585
|
selector: 'praxis-expansion',
|
|
600
1586
|
component: PraxisExpansion,
|
|
601
1587
|
friendlyName: 'Praxis Expansion Panel',
|
|
602
|
-
description: 'Acordeão/Painéis de expansão configuráveis por metadata,
|
|
1588
|
+
description: 'Acordeão/Painéis de expansão configuráveis por metadata, com aparência e tokens M3.',
|
|
603
1589
|
icon: 'unfold_more',
|
|
604
1590
|
inputs: [
|
|
605
|
-
{ name: 'config', type: 'ExpansionMetadata', label: 'Configuração', description: 'Configuração JSON (acordeão e painéis)' },
|
|
606
|
-
{ name: 'expansionId', type: 'string', label: 'ID', description: 'Identificador para persistência
|
|
607
|
-
{ name: '
|
|
1591
|
+
{ name: 'config', type: 'ExpansionMetadata', label: 'Configuração', description: 'Configuração JSON (acordeão, aparência e painéis)' },
|
|
1592
|
+
{ name: 'expansionId', type: 'string', label: 'ID', description: 'Identificador para persistência (obrigatório)' },
|
|
1593
|
+
{ name: 'componentInstanceId', type: 'string', label: 'ID da instância', description: 'Identificador opcional para múltiplas instâncias na mesma rota' },
|
|
1594
|
+
{ name: 'enableCustomization', type: 'boolean', default: false, label: 'Modo de customização' },
|
|
608
1595
|
{ name: 'context', type: 'Record<string, any>', label: 'Contexto' },
|
|
609
1596
|
{ name: 'strictValidation', type: 'boolean', default: true },
|
|
610
1597
|
{ name: 'defaultOptions', type: 'MatExpansionPanelDefaultOptions', label: 'Opções padrão do painel' },
|
|
@@ -618,6 +1605,60 @@ const PRAXIS_EXPANSION_COMPONENT_METADATA = {
|
|
|
618
1605
|
{ name: 'destroyed', type: '{ panelId?: string; panelIndex: number }', label: 'Destruído' },
|
|
619
1606
|
{ name: 'widgetEvent', type: '{ panelId?: string; panelIndex?: number; sourceId: string; output?: string; payload?: any }', label: 'Evento interno' },
|
|
620
1607
|
],
|
|
1608
|
+
actions: [
|
|
1609
|
+
{
|
|
1610
|
+
id: 'panel-opened',
|
|
1611
|
+
label: 'Painel aberto',
|
|
1612
|
+
icon: 'unfold_more',
|
|
1613
|
+
description: 'Emite evento ao abrir um painel',
|
|
1614
|
+
emit: 'opened',
|
|
1615
|
+
payloadSchema: {
|
|
1616
|
+
type: 'object',
|
|
1617
|
+
properties: {
|
|
1618
|
+
panelId: { type: 'string', description: 'ID do painel' },
|
|
1619
|
+
panelIndex: { type: 'number', description: 'Índice do painel' },
|
|
1620
|
+
},
|
|
1621
|
+
required: ['panelIndex'],
|
|
1622
|
+
example: { panelIndex: 0 },
|
|
1623
|
+
},
|
|
1624
|
+
scope: 'context',
|
|
1625
|
+
},
|
|
1626
|
+
{
|
|
1627
|
+
id: 'panel-closed',
|
|
1628
|
+
label: 'Painel fechado',
|
|
1629
|
+
icon: 'unfold_less',
|
|
1630
|
+
description: 'Emite evento ao fechar um painel',
|
|
1631
|
+
emit: 'closed',
|
|
1632
|
+
payloadSchema: {
|
|
1633
|
+
type: 'object',
|
|
1634
|
+
properties: {
|
|
1635
|
+
panelId: { type: 'string', description: 'ID do painel' },
|
|
1636
|
+
panelIndex: { type: 'number', description: 'Índice do painel' },
|
|
1637
|
+
},
|
|
1638
|
+
required: ['panelIndex'],
|
|
1639
|
+
example: { panelIndex: 0 },
|
|
1640
|
+
},
|
|
1641
|
+
scope: 'context',
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
id: 'panel-toggle',
|
|
1645
|
+
label: 'Alternar painel',
|
|
1646
|
+
icon: 'open_in_full',
|
|
1647
|
+
description: 'Emite evento ao alternar expansão do painel',
|
|
1648
|
+
emit: 'expandedChange',
|
|
1649
|
+
payloadSchema: {
|
|
1650
|
+
type: 'object',
|
|
1651
|
+
properties: {
|
|
1652
|
+
panelId: { type: 'string', description: 'ID do painel' },
|
|
1653
|
+
panelIndex: { type: 'number', description: 'Índice do painel' },
|
|
1654
|
+
expanded: { type: 'boolean', description: 'Estado expandido' },
|
|
1655
|
+
},
|
|
1656
|
+
required: ['panelIndex', 'expanded'],
|
|
1657
|
+
example: { panelIndex: 0, expanded: true },
|
|
1658
|
+
},
|
|
1659
|
+
scope: 'context',
|
|
1660
|
+
},
|
|
1661
|
+
],
|
|
621
1662
|
tags: ['widget', 'expansion', 'accordion', 'configurable'],
|
|
622
1663
|
lib: '@praxisui/expansion',
|
|
623
1664
|
};
|
|
@@ -638,11 +1679,10 @@ function providePraxisExpansionDefaults(opts) {
|
|
|
638
1679
|
/*
|
|
639
1680
|
* Public API Surface of praxis-expansion
|
|
640
1681
|
*/
|
|
641
|
-
// Editor é exportado pelo mesmo arquivo de componente (praxis-expansion.ts)
|
|
642
1682
|
|
|
643
1683
|
/**
|
|
644
1684
|
* Generated bundle index. Do not edit.
|
|
645
1685
|
*/
|
|
646
1686
|
|
|
647
|
-
export { PRAXIS_EXPANSION_COMPONENT_METADATA, PraxisExpansion, PraxisExpansionConfigEditor, providePraxisExpansionDefaults, providePraxisExpansionMetadata };
|
|
1687
|
+
export { EXPANSION_AI_CAPABILITIES, PRAXIS_EXPANSION_COMPONENT_METADATA, PraxisExpansion, PraxisExpansionConfigEditor, providePraxisExpansionDefaults, providePraxisExpansionMetadata };
|
|
648
1688
|
//# sourceMappingURL=praxisui-expansion.mjs.map
|