@yourself.create/ngx-form-designer 0.0.4 → 0.0.5
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/fesm2022/uch-web-ngx-form-designer.mjs +1498 -1011
- package/fesm2022/uch-web-ngx-form-designer.mjs.map +1 -1
- package/lib/form-core/models.d.ts +0 -11
- package/lib/form-designer/designer-state.service.d.ts +35 -1
- package/lib/form-designer/dynamic-properties/dynamic-properties.component.d.ts +3 -5
- package/lib/form-designer/form-preview.component.d.ts +1 -1
- package/lib/form-designer/inspector-sections/inspector-transform-section.component.d.ts +12 -0
- package/lib/form-designer/layout-canvas.component.d.ts +12 -2
- package/lib/form-designer/properties-panel.component.d.ts +4 -0
- package/lib/form-renderer/json-form-renderer.component.d.ts +24 -1
- package/lib/form-renderer/layout-node.component.d.ts +10 -0
- package/lib/website/website-preview-shell.component.d.ts +1 -1
- package/lib/widgets/widget-definition.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { v4 } from 'uuid';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { Injectable, InjectionToken, NgModule, inject, signal, computed, EventEmitter, DestroyRef, Injector, afterNextRender, ViewContainerRef, Input, ViewChild, Output, Inject, ChangeDetectionStrategy, Component, effect, ElementRef, NgZone, input, output, HostListener,
|
|
3
|
+
import { Injectable, InjectionToken, NgModule, inject, signal, computed, EventEmitter, DestroyRef, Injector, afterNextRender, ViewContainerRef, Input, ViewChild, Output, Inject, ChangeDetectionStrategy, Component, effect, ElementRef, NgZone, input, output, HostListener, untracked, ChangeDetectorRef, Pipe, ContentChildren } from '@angular/core';
|
|
4
4
|
import { BehaviorSubject, Subject, merge, of, filter, map, debounceTime as debounceTime$1, skip, firstValueFrom } from 'rxjs';
|
|
5
5
|
import * as i1 from '@angular/common';
|
|
6
6
|
import { CommonModule, DOCUMENT } from '@angular/common';
|
|
@@ -491,18 +491,9 @@ class FormEngine {
|
|
|
491
491
|
const field = this.getFieldById(fieldId);
|
|
492
492
|
if (!field)
|
|
493
493
|
return false;
|
|
494
|
-
// 1. Legacy
|
|
495
|
-
if (field.conditionalVisibility) {
|
|
496
|
-
const cv = field.conditionalVisibility;
|
|
497
|
-
const val = this.values[cv.fieldName];
|
|
498
|
-
if (cv.operator === 'equals' && val !== cv.value)
|
|
499
|
-
return false;
|
|
500
|
-
if (cv.operator === 'notEquals' && val === cv.value)
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
// 2. Dependencies (Legacy)
|
|
494
|
+
// 1. Dependencies (Legacy)
|
|
504
495
|
let visible = this.evaluateDependencyRules(field, 'show', 'hide', true);
|
|
505
|
-
//
|
|
496
|
+
// 2. Enterprise Rules
|
|
506
497
|
visible = this.evaluateEnterpriseRules(field, 'visible', 'hidden', visible);
|
|
507
498
|
return visible;
|
|
508
499
|
}
|
|
@@ -823,6 +814,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
823
814
|
}]
|
|
824
815
|
}] });
|
|
825
816
|
|
|
817
|
+
const TRANSFORM_CONTROL_KEYS = new Set([
|
|
818
|
+
'transformX',
|
|
819
|
+
'transformY',
|
|
820
|
+
'transformZ',
|
|
821
|
+
'rotate',
|
|
822
|
+
'scale'
|
|
823
|
+
]);
|
|
826
824
|
const WRAPPER_SURFACE_STYLE_KEYS = new Set([
|
|
827
825
|
'backgroundColor',
|
|
828
826
|
'borderColor',
|
|
@@ -860,10 +858,13 @@ function normalizeStyle$1(style) {
|
|
|
860
858
|
if (!style)
|
|
861
859
|
return {};
|
|
862
860
|
const result = {};
|
|
861
|
+
const transform = buildTransform(style);
|
|
863
862
|
Object.keys(style).forEach(key => {
|
|
864
863
|
const value = style[key];
|
|
865
864
|
if (value === undefined || value === null || value === '')
|
|
866
865
|
return;
|
|
866
|
+
if (TRANSFORM_CONTROL_KEYS.has(key))
|
|
867
|
+
return;
|
|
867
868
|
// 1. Check for Spacing Tokens (padding*, margin*, gap)
|
|
868
869
|
// Only map known tokens to avoid accidental string matching
|
|
869
870
|
const isSpacing = /^(padding|margin|gap)/i.test(key);
|
|
@@ -892,6 +893,10 @@ function normalizeStyle$1(style) {
|
|
|
892
893
|
}
|
|
893
894
|
result[key] = value;
|
|
894
895
|
});
|
|
896
|
+
if (transform) {
|
|
897
|
+
const existingTransform = typeof result['transform'] === 'string' ? result['transform'].trim() : '';
|
|
898
|
+
result['transform'] = existingTransform ? `${existingTransform} ${transform}` : transform;
|
|
899
|
+
}
|
|
895
900
|
return result;
|
|
896
901
|
}
|
|
897
902
|
function mergeAndNormalize(base, override) {
|
|
@@ -930,6 +935,75 @@ function hasWrapperSurfaceStyles(style) {
|
|
|
930
935
|
}
|
|
931
936
|
return Object.keys(style).some(key => WRAPPER_SURFACE_STYLE_KEYS.has(key));
|
|
932
937
|
}
|
|
938
|
+
function buildTransform(style) {
|
|
939
|
+
const transforms = [];
|
|
940
|
+
const translateX = normalizeLength(style['transformX']);
|
|
941
|
+
const translateY = normalizeLength(style['transformY']);
|
|
942
|
+
const translateZ = normalizeLength(style['transformZ']);
|
|
943
|
+
const rotate = normalizeAngle(style['rotate']);
|
|
944
|
+
const scale = normalizeScale(style['scale']);
|
|
945
|
+
if (translateX || translateY || translateZ) {
|
|
946
|
+
transforms.push(`translate3d(${translateX ?? '0px'}, ${translateY ?? '0px'}, ${translateZ ?? '0px'})`);
|
|
947
|
+
}
|
|
948
|
+
if (rotate) {
|
|
949
|
+
transforms.push(`rotate(${rotate})`);
|
|
950
|
+
}
|
|
951
|
+
if (scale) {
|
|
952
|
+
transforms.push(`scale(${scale})`);
|
|
953
|
+
}
|
|
954
|
+
return transforms.join(' ');
|
|
955
|
+
}
|
|
956
|
+
function normalizeLength(value) {
|
|
957
|
+
if (value === undefined || value === null || value === '') {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
961
|
+
return `${value}px`;
|
|
962
|
+
}
|
|
963
|
+
if (typeof value === 'string') {
|
|
964
|
+
const trimmed = value.trim();
|
|
965
|
+
if (!trimmed) {
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
969
|
+
return `${trimmed}px`;
|
|
970
|
+
}
|
|
971
|
+
return trimmed;
|
|
972
|
+
}
|
|
973
|
+
return null;
|
|
974
|
+
}
|
|
975
|
+
function normalizeAngle(value) {
|
|
976
|
+
if (value === undefined || value === null || value === '') {
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
979
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
980
|
+
return `${value}deg`;
|
|
981
|
+
}
|
|
982
|
+
if (typeof value === 'string') {
|
|
983
|
+
const trimmed = value.trim();
|
|
984
|
+
if (!trimmed) {
|
|
985
|
+
return null;
|
|
986
|
+
}
|
|
987
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
988
|
+
return `${trimmed}deg`;
|
|
989
|
+
}
|
|
990
|
+
return trimmed;
|
|
991
|
+
}
|
|
992
|
+
return null;
|
|
993
|
+
}
|
|
994
|
+
function normalizeScale(value) {
|
|
995
|
+
if (value === undefined || value === null || value === '') {
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
999
|
+
return String(value);
|
|
1000
|
+
}
|
|
1001
|
+
if (typeof value === 'string') {
|
|
1002
|
+
const trimmed = value.trim();
|
|
1003
|
+
return trimmed || null;
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
933
1007
|
|
|
934
1008
|
const WIDGET_EDITOR_CONTEXT = new InjectionToken('WIDGET_EDITOR_CONTEXT');
|
|
935
1009
|
|
|
@@ -1023,6 +1097,7 @@ class DesignerStateService {
|
|
|
1023
1097
|
isReadOnly = signal(false);
|
|
1024
1098
|
// Structure of clipboard data
|
|
1025
1099
|
clipboard = signal(null);
|
|
1100
|
+
pendingFieldInsert = signal(null);
|
|
1026
1101
|
history = [];
|
|
1027
1102
|
historyIndex = signal(-1);
|
|
1028
1103
|
historyLength = signal(0);
|
|
@@ -1043,6 +1118,21 @@ class DesignerStateService {
|
|
|
1043
1118
|
const entry = this.layoutIndex()[id];
|
|
1044
1119
|
return entry?.node ?? null;
|
|
1045
1120
|
});
|
|
1121
|
+
selectedEntry = computed(() => {
|
|
1122
|
+
const id = this.selectedNodeId();
|
|
1123
|
+
if (!id)
|
|
1124
|
+
return null;
|
|
1125
|
+
return this.layoutIndex()[id] ?? null;
|
|
1126
|
+
});
|
|
1127
|
+
selectedColumnId = computed(() => this.findSelectionColumnEntry(this.selectedEntry())?.path.at(-1) ?? null);
|
|
1128
|
+
selectedRowId = computed(() => this.findSelectionRowEntry(this.selectedEntry())?.path.at(-1) ?? null);
|
|
1129
|
+
canInsertColumnBeforeSelection = computed(() => !!this.resolveColumnInsertTarget(this.selectedEntry()));
|
|
1130
|
+
canInsertColumnAfterSelection = computed(() => !!this.resolveColumnInsertTarget(this.selectedEntry()));
|
|
1131
|
+
canInsertRowInSelectedColumn = computed(() => !!this.findSelectionColumnEntry(this.selectedEntry()));
|
|
1132
|
+
canInsertRowBeforeSelection = computed(() => !!this.resolveRelativeRowInsertTarget(this.selectedEntry()));
|
|
1133
|
+
canInsertRowAfterSelection = computed(() => !!this.resolveRelativeRowInsertTarget(this.selectedEntry()));
|
|
1134
|
+
canArmFieldInsertBeforeSelection = computed(() => !!this.getSelectedFieldReference());
|
|
1135
|
+
canArmFieldInsertAfterSelection = computed(() => !!this.getSelectedFieldReference());
|
|
1046
1136
|
selectedField = computed(() => {
|
|
1047
1137
|
const selectedId = this.selectedNodeId();
|
|
1048
1138
|
if (!selectedId)
|
|
@@ -1091,6 +1181,7 @@ class DesignerStateService {
|
|
|
1091
1181
|
this.restoreSnapshot(nextIndex);
|
|
1092
1182
|
}
|
|
1093
1183
|
selectNode(id) {
|
|
1184
|
+
this.pendingFieldInsert.set(null);
|
|
1094
1185
|
if (!id) {
|
|
1095
1186
|
this.selectedNodeId.set(null);
|
|
1096
1187
|
this.selectedNodeIds.set([]);
|
|
@@ -1102,6 +1193,7 @@ class DesignerStateService {
|
|
|
1102
1193
|
this.closeContextMenu();
|
|
1103
1194
|
}
|
|
1104
1195
|
toggleNodeSelection(id) {
|
|
1196
|
+
this.pendingFieldInsert.set(null);
|
|
1105
1197
|
const current = this.selectedNodeIds();
|
|
1106
1198
|
const exists = current.includes(id);
|
|
1107
1199
|
const next = exists ? current.filter(item => item !== id) : [...current, id];
|
|
@@ -1116,6 +1208,14 @@ class DesignerStateService {
|
|
|
1116
1208
|
isNodeSelected(nodeId) {
|
|
1117
1209
|
return this.selectedNodeIds().includes(nodeId);
|
|
1118
1210
|
}
|
|
1211
|
+
isSelectionRowAncestor(nodeId) {
|
|
1212
|
+
const selectedId = this.selectedNodeId();
|
|
1213
|
+
return !!selectedId && selectedId !== nodeId && this.selectedRowId() === nodeId;
|
|
1214
|
+
}
|
|
1215
|
+
isSelectionColumnAncestor(nodeId) {
|
|
1216
|
+
const selectedId = this.selectedNodeId();
|
|
1217
|
+
return !!selectedId && selectedId !== nodeId && this.selectedColumnId() === nodeId;
|
|
1218
|
+
}
|
|
1119
1219
|
composeScopedNodeId(scopePath, nodeId) {
|
|
1120
1220
|
return composeScopedNodeId(scopePath, nodeId);
|
|
1121
1221
|
}
|
|
@@ -1364,6 +1464,7 @@ class DesignerStateService {
|
|
|
1364
1464
|
}
|
|
1365
1465
|
};
|
|
1366
1466
|
removeRecursive(scopeSchema.layout);
|
|
1467
|
+
this.pruneEmptyRows(scopeSchema.layout);
|
|
1367
1468
|
scopeSchema.fields = scopeSchema.fields.filter(field => !fieldsToRemove.has(field.id));
|
|
1368
1469
|
}
|
|
1369
1470
|
this.setSchema(nextSchema);
|
|
@@ -1559,20 +1660,67 @@ class DesignerStateService {
|
|
|
1559
1660
|
const selectedId = this.selectedNodeId();
|
|
1560
1661
|
const selectedEntry = selectedId ? this.layoutIndex()[selectedId] : undefined;
|
|
1561
1662
|
const insertionScopePath = this.resolveInsertionScopePath(selectedEntry);
|
|
1663
|
+
const pendingFieldInsert = this.pendingFieldInsert();
|
|
1664
|
+
const canInsertRelativeToSelectedWidget = !!selectedEntry
|
|
1665
|
+
&& selectedEntry.node.type === 'widget'
|
|
1666
|
+
&& this.sameScope(selectedEntry.scopePath, insertionScopePath)
|
|
1667
|
+
&& !!selectedEntry.node.refId;
|
|
1562
1668
|
const nextSchema = this.cloneValue(current);
|
|
1563
1669
|
const targetSchema = this.resolveSchemaAtScope(nextSchema, insertionScopePath);
|
|
1564
1670
|
if (!targetSchema)
|
|
1565
1671
|
return;
|
|
1566
|
-
const targetCol = this.resolveTargetColumnForFieldInsert(targetSchema, selectedEntry, insertionScopePath);
|
|
1567
|
-
if (!targetCol)
|
|
1568
|
-
return;
|
|
1569
1672
|
const inserted = this.createInsertedWidgets(widgetDef, widgetDef.type);
|
|
1570
|
-
|
|
1571
|
-
|
|
1673
|
+
const targetedInsert = pendingFieldInsert
|
|
1674
|
+
? this.resolveProgrammaticFieldInsertTarget(nextSchema, {
|
|
1675
|
+
referenceFieldId: pendingFieldInsert.referenceFieldId,
|
|
1676
|
+
position: pendingFieldInsert.position
|
|
1677
|
+
})
|
|
1678
|
+
: canInsertRelativeToSelectedWidget
|
|
1679
|
+
? this.resolveProgrammaticFieldInsertTarget(nextSchema, {
|
|
1680
|
+
referenceFieldId: selectedEntry.node.refId,
|
|
1681
|
+
position: 'after'
|
|
1682
|
+
})
|
|
1683
|
+
: null;
|
|
1684
|
+
if (targetedInsert) {
|
|
1685
|
+
targetedInsert.schema.fields.push(...inserted.fields);
|
|
1686
|
+
targetedInsert.column.children.splice(targetedInsert.index, 0, ...inserted.nodes);
|
|
1687
|
+
}
|
|
1688
|
+
else {
|
|
1689
|
+
const targetCol = this.resolveTargetColumnForFieldInsert(targetSchema, selectedEntry, insertionScopePath);
|
|
1690
|
+
if (!targetCol)
|
|
1691
|
+
return;
|
|
1692
|
+
targetSchema.fields.push(...inserted.fields);
|
|
1693
|
+
targetCol.children.push(...inserted.nodes);
|
|
1694
|
+
}
|
|
1695
|
+
this.pendingFieldInsert.set(null);
|
|
1572
1696
|
this.setSchema(nextSchema);
|
|
1573
1697
|
const primaryNode = inserted.primaryNode;
|
|
1574
1698
|
this.selectNode(this.composeScopedNodeId(insertionScopePath, primaryNode.id));
|
|
1575
1699
|
}
|
|
1700
|
+
insertColumnBeforeSelection() {
|
|
1701
|
+
this.insertColumnRelativeToSelection('before');
|
|
1702
|
+
}
|
|
1703
|
+
insertColumnAfterSelection() {
|
|
1704
|
+
this.insertColumnRelativeToSelection('after');
|
|
1705
|
+
}
|
|
1706
|
+
insertRowBeforeSelection() {
|
|
1707
|
+
this.insertRowRelativeToSelection('before');
|
|
1708
|
+
}
|
|
1709
|
+
insertRowAfterSelection() {
|
|
1710
|
+
this.insertRowRelativeToSelection('after');
|
|
1711
|
+
}
|
|
1712
|
+
insertRowInSelectedColumn() {
|
|
1713
|
+
const columnEntry = this.findSelectionColumnEntry(this.selectedEntry());
|
|
1714
|
+
if (!columnEntry)
|
|
1715
|
+
return;
|
|
1716
|
+
this.insertRowInColumn(columnEntry.path.at(-1) ?? columnEntry.rawNodeId, 1);
|
|
1717
|
+
}
|
|
1718
|
+
armFieldInsertBeforeSelection() {
|
|
1719
|
+
this.armFieldInsertForSelection('before');
|
|
1720
|
+
}
|
|
1721
|
+
armFieldInsertAfterSelection() {
|
|
1722
|
+
this.armFieldInsertForSelection('after');
|
|
1723
|
+
}
|
|
1576
1724
|
insertField(options) {
|
|
1577
1725
|
if (this.isReadOnly())
|
|
1578
1726
|
return null;
|
|
@@ -1969,11 +2117,21 @@ class DesignerStateService {
|
|
|
1969
2117
|
const scopeSchema = this.resolveSchemaAtScope(newSchema, entry.scopePath);
|
|
1970
2118
|
if (!scopeSchema)
|
|
1971
2119
|
return;
|
|
2120
|
+
const fieldsToRemove = new Set();
|
|
2121
|
+
const collectFieldIds = (node) => {
|
|
2122
|
+
if (node.type === 'widget' && node.refId) {
|
|
2123
|
+
fieldsToRemove.add(node.refId);
|
|
2124
|
+
}
|
|
2125
|
+
if (node.type === 'row' || node.type === 'col') {
|
|
2126
|
+
node.children.forEach(child => collectFieldIds(child));
|
|
2127
|
+
}
|
|
2128
|
+
};
|
|
1972
2129
|
// Find parent row and remove column
|
|
1973
2130
|
const removeFromRow = (node) => {
|
|
1974
2131
|
if (node.type === 'row') {
|
|
1975
2132
|
const idx = node.children.findIndex(c => c.id === entry.rawNodeId && c.type === 'col');
|
|
1976
2133
|
if (idx !== -1) {
|
|
2134
|
+
collectFieldIds(node.children[idx]);
|
|
1977
2135
|
node.children.splice(idx, 1);
|
|
1978
2136
|
return true;
|
|
1979
2137
|
}
|
|
@@ -1987,6 +2145,8 @@ class DesignerStateService {
|
|
|
1987
2145
|
return false;
|
|
1988
2146
|
};
|
|
1989
2147
|
removeFromRow(scopeSchema.layout);
|
|
2148
|
+
this.pruneEmptyRows(scopeSchema.layout);
|
|
2149
|
+
scopeSchema.fields = scopeSchema.fields.filter(field => !fieldsToRemove.has(field.id));
|
|
1990
2150
|
this.setSchema(newSchema);
|
|
1991
2151
|
}
|
|
1992
2152
|
/** Set preset column layout (e.g., 3,4,6) on a row */
|
|
@@ -2199,6 +2359,7 @@ class DesignerStateService {
|
|
|
2199
2359
|
return false;
|
|
2200
2360
|
};
|
|
2201
2361
|
removeFromParent(scopeSchema.layout, entry.rawNodeId);
|
|
2362
|
+
this.pruneEmptyRows(scopeSchema.layout);
|
|
2202
2363
|
scopeSchema.fields = scopeSchema.fields.filter(field => !fieldsToRemove.has(field.id));
|
|
2203
2364
|
// Clear selection
|
|
2204
2365
|
if (this.selectedNodeId() === nodeId || this.selectedNodeId() === this.composeScopedNodeId(entry.scopePath, entry.rawNodeId)) {
|
|
@@ -2418,6 +2579,22 @@ class DesignerStateService {
|
|
|
2418
2579
|
return null;
|
|
2419
2580
|
return selectedEntry;
|
|
2420
2581
|
}
|
|
2582
|
+
findSelectionColumnEntry(entry) {
|
|
2583
|
+
return this.findAncestorEntryByType(entry, 'col');
|
|
2584
|
+
}
|
|
2585
|
+
findSelectionRowEntry(entry) {
|
|
2586
|
+
return this.findAncestorEntryByType(entry, 'row');
|
|
2587
|
+
}
|
|
2588
|
+
findAncestorEntryByType(entry, type) {
|
|
2589
|
+
let cursor = entry;
|
|
2590
|
+
while (cursor) {
|
|
2591
|
+
if (cursor.node.type === type) {
|
|
2592
|
+
return cursor;
|
|
2593
|
+
}
|
|
2594
|
+
cursor = cursor.parentId ? this.layoutIndex()[cursor.parentId] : null;
|
|
2595
|
+
}
|
|
2596
|
+
return null;
|
|
2597
|
+
}
|
|
2421
2598
|
resolveSchemaAtScope(root, scopePath) {
|
|
2422
2599
|
let cursor = root;
|
|
2423
2600
|
for (const repeatableFieldId of scopePath) {
|
|
@@ -2464,6 +2641,102 @@ class DesignerStateService {
|
|
|
2464
2641
|
}
|
|
2465
2642
|
return this.findFirstColumn(targetSchema.layout);
|
|
2466
2643
|
}
|
|
2644
|
+
resolveColumnInsertTarget(selectionEntry) {
|
|
2645
|
+
const columnEntry = this.findSelectionColumnEntry(selectionEntry);
|
|
2646
|
+
const rowEntry = this.findSelectionRowEntry(selectionEntry);
|
|
2647
|
+
if (!columnEntry || !rowEntry)
|
|
2648
|
+
return null;
|
|
2649
|
+
return { rowEntry, columnEntry };
|
|
2650
|
+
}
|
|
2651
|
+
insertColumnRelativeToSelection(position) {
|
|
2652
|
+
if (this.isReadOnly())
|
|
2653
|
+
return;
|
|
2654
|
+
const target = this.resolveColumnInsertTarget(this.selectedEntry());
|
|
2655
|
+
if (!target)
|
|
2656
|
+
return;
|
|
2657
|
+
const current = this.schema();
|
|
2658
|
+
const nextSchema = this.cloneValue(current);
|
|
2659
|
+
const scopeSchema = this.resolveSchemaAtScope(nextSchema, target.rowEntry.scopePath);
|
|
2660
|
+
if (!scopeSchema)
|
|
2661
|
+
return;
|
|
2662
|
+
const rowNode = this.findNode(scopeSchema.layout, target.rowEntry.rawNodeId);
|
|
2663
|
+
const selectedColumn = this.findNode(scopeSchema.layout, target.columnEntry.rawNodeId);
|
|
2664
|
+
if (rowNode?.type !== 'row' || selectedColumn?.type !== 'col')
|
|
2665
|
+
return;
|
|
2666
|
+
const insertIndex = position === 'before' ? target.columnEntry.index : target.columnEntry.index + 1;
|
|
2667
|
+
const nextColumn = {
|
|
2668
|
+
id: v4(),
|
|
2669
|
+
type: 'col',
|
|
2670
|
+
responsive: this.cloneValue(selectedColumn.responsive ?? { xs: 12 }),
|
|
2671
|
+
children: []
|
|
2672
|
+
};
|
|
2673
|
+
rowNode.children.splice(insertIndex, 0, nextColumn);
|
|
2674
|
+
this.setSchema(nextSchema);
|
|
2675
|
+
this.selectNode(this.composeScopedNodeId(target.rowEntry.scopePath, nextColumn.id));
|
|
2676
|
+
}
|
|
2677
|
+
resolveRelativeRowInsertTarget(selectionEntry) {
|
|
2678
|
+
if (!selectionEntry)
|
|
2679
|
+
return null;
|
|
2680
|
+
if (selectionEntry.node.type === 'widget') {
|
|
2681
|
+
const containerEntry = this.findSelectionColumnEntry(selectionEntry);
|
|
2682
|
+
if (!containerEntry)
|
|
2683
|
+
return null;
|
|
2684
|
+
return { containerEntry, referenceIndex: selectionEntry.index };
|
|
2685
|
+
}
|
|
2686
|
+
if (selectionEntry.node.type === 'row') {
|
|
2687
|
+
const containerEntry = selectionEntry.parentId
|
|
2688
|
+
? this.findAncestorEntryByType(this.layoutIndex()[selectionEntry.parentId], 'col')
|
|
2689
|
+
: null;
|
|
2690
|
+
if (!containerEntry)
|
|
2691
|
+
return null;
|
|
2692
|
+
return { containerEntry, referenceIndex: selectionEntry.index };
|
|
2693
|
+
}
|
|
2694
|
+
return null;
|
|
2695
|
+
}
|
|
2696
|
+
insertRowRelativeToSelection(position) {
|
|
2697
|
+
if (this.isReadOnly())
|
|
2698
|
+
return;
|
|
2699
|
+
const target = this.resolveRelativeRowInsertTarget(this.selectedEntry());
|
|
2700
|
+
if (!target)
|
|
2701
|
+
return;
|
|
2702
|
+
const current = this.schema();
|
|
2703
|
+
const nextSchema = this.cloneValue(current);
|
|
2704
|
+
const scopeSchema = this.resolveSchemaAtScope(nextSchema, target.containerEntry.scopePath);
|
|
2705
|
+
if (!scopeSchema)
|
|
2706
|
+
return;
|
|
2707
|
+
const container = this.findNode(scopeSchema.layout, target.containerEntry.rawNodeId);
|
|
2708
|
+
if (container?.type !== 'col')
|
|
2709
|
+
return;
|
|
2710
|
+
const nextRow = {
|
|
2711
|
+
id: v4(),
|
|
2712
|
+
type: 'row',
|
|
2713
|
+
children: [
|
|
2714
|
+
{
|
|
2715
|
+
id: v4(),
|
|
2716
|
+
type: 'col',
|
|
2717
|
+
responsive: { xs: 12 },
|
|
2718
|
+
children: []
|
|
2719
|
+
}
|
|
2720
|
+
]
|
|
2721
|
+
};
|
|
2722
|
+
const insertIndex = position === 'before' ? target.referenceIndex : target.referenceIndex + 1;
|
|
2723
|
+
container.children.splice(insertIndex, 0, nextRow);
|
|
2724
|
+
this.setSchema(nextSchema);
|
|
2725
|
+
this.selectNode(this.composeScopedNodeId(target.containerEntry.scopePath, nextRow.children[0].id));
|
|
2726
|
+
}
|
|
2727
|
+
armFieldInsertForSelection(position) {
|
|
2728
|
+
const referenceFieldId = this.getSelectedFieldReference();
|
|
2729
|
+
if (!referenceFieldId)
|
|
2730
|
+
return;
|
|
2731
|
+
this.pendingFieldInsert.set({ referenceFieldId, position });
|
|
2732
|
+
}
|
|
2733
|
+
getSelectedFieldReference() {
|
|
2734
|
+
const entry = this.selectedEntry();
|
|
2735
|
+
if (!entry || entry.node.type !== 'widget')
|
|
2736
|
+
return null;
|
|
2737
|
+
const refId = entry.node.refId;
|
|
2738
|
+
return typeof refId === 'string' && refId.trim().length > 0 ? refId : null;
|
|
2739
|
+
}
|
|
2467
2740
|
resolveFieldWidgetDefinition(widgetId, type) {
|
|
2468
2741
|
if (widgetId) {
|
|
2469
2742
|
const byId = this.widgetDefs.find(widget => widget.id === widgetId);
|
|
@@ -2657,6 +2930,20 @@ class DesignerStateService {
|
|
|
2657
2930
|
const [removed] = children.splice(result.index, 1);
|
|
2658
2931
|
return removed ?? null;
|
|
2659
2932
|
}
|
|
2933
|
+
pruneEmptyRows(node) {
|
|
2934
|
+
if (node.type === 'widget') {
|
|
2935
|
+
return true;
|
|
2936
|
+
}
|
|
2937
|
+
if (node.type === 'col') {
|
|
2938
|
+
node.children = node.children.filter(child => this.pruneEmptyRows(child));
|
|
2939
|
+
return true;
|
|
2940
|
+
}
|
|
2941
|
+
if (node.type === 'row') {
|
|
2942
|
+
node.children = node.children.filter(child => this.pruneEmptyRows(child));
|
|
2943
|
+
return node.children.length > 0;
|
|
2944
|
+
}
|
|
2945
|
+
return true;
|
|
2946
|
+
}
|
|
2660
2947
|
findWidgetByRefId(node, refId) {
|
|
2661
2948
|
if (node.type === 'widget' && node.refId === refId) {
|
|
2662
2949
|
return node;
|
|
@@ -2863,6 +3150,12 @@ class LayoutNodeComponent {
|
|
|
2863
3150
|
get isSelected() {
|
|
2864
3151
|
return this.designerState.isNodeSelected(this.getScopedNodeId(this.node.id));
|
|
2865
3152
|
}
|
|
3153
|
+
get isRowSelectionAncestor() {
|
|
3154
|
+
return this.node.type === 'row' && this.designerState.isSelectionRowAncestor(this.getScopedNodeId(this.node.id));
|
|
3155
|
+
}
|
|
3156
|
+
get isColumnSelectionAncestor() {
|
|
3157
|
+
return this.node.type === 'col' && this.designerState.isSelectionColumnAncestor(this.getScopedNodeId(this.node.id));
|
|
3158
|
+
}
|
|
2866
3159
|
get isResizing() {
|
|
2867
3160
|
return this.activeResizeNodeId === this.node.id;
|
|
2868
3161
|
}
|
|
@@ -2961,6 +3254,24 @@ class LayoutNodeComponent {
|
|
|
2961
3254
|
wrapWidgetInRow() {
|
|
2962
3255
|
this.designerState.wrapWidgetInRow(this.getScopedNodeId(this.node.id));
|
|
2963
3256
|
}
|
|
3257
|
+
decreaseSelectedColumnSpan() {
|
|
3258
|
+
this.adjustSelectedColumnSpan(-1);
|
|
3259
|
+
}
|
|
3260
|
+
increaseSelectedColumnSpan() {
|
|
3261
|
+
this.adjustSelectedColumnSpan(1);
|
|
3262
|
+
}
|
|
3263
|
+
canDecreaseSelectedColumnSpan() {
|
|
3264
|
+
const span = this.getSelectedColumnSpan();
|
|
3265
|
+
return span !== null && span > LayoutNodeComponent.MIN_COLUMN_SPAN;
|
|
3266
|
+
}
|
|
3267
|
+
canIncreaseSelectedColumnSpan() {
|
|
3268
|
+
const span = this.getSelectedColumnSpan();
|
|
3269
|
+
return span !== null && span < LayoutNodeComponent.MAX_COLUMN_SPAN;
|
|
3270
|
+
}
|
|
3271
|
+
getSelectedColumnSpanLabel() {
|
|
3272
|
+
const span = this.getSelectedColumnSpan();
|
|
3273
|
+
return span === null ? '--/12' : `${span}/12`;
|
|
3274
|
+
}
|
|
2964
3275
|
getNodeTypeLabel() {
|
|
2965
3276
|
if (this.node.type === 'widget') {
|
|
2966
3277
|
const widgetNode = this.node;
|
|
@@ -3270,6 +3581,32 @@ class LayoutNodeComponent {
|
|
|
3270
3581
|
node.responsive[this.breakpoint] = nextSpan;
|
|
3271
3582
|
this.cdr.detectChanges();
|
|
3272
3583
|
}
|
|
3584
|
+
adjustSelectedColumnSpan(delta) {
|
|
3585
|
+
const columnEntry = this.getSelectedColumnEntry();
|
|
3586
|
+
const column = columnEntry?.node;
|
|
3587
|
+
if (!column || column.type !== 'col')
|
|
3588
|
+
return;
|
|
3589
|
+
const responsive = { ...(column.responsive ?? { xs: LayoutNodeComponent.MAX_COLUMN_SPAN }) };
|
|
3590
|
+
const currentSpan = this.getEffectiveSpan(responsive);
|
|
3591
|
+
const nextSpan = Math.max(LayoutNodeComponent.MIN_COLUMN_SPAN, Math.min(LayoutNodeComponent.MAX_COLUMN_SPAN, currentSpan + delta));
|
|
3592
|
+
if (nextSpan === currentSpan)
|
|
3593
|
+
return;
|
|
3594
|
+
responsive[this.breakpoint] = nextSpan;
|
|
3595
|
+
this.designerState.updateNodeResponsive(columnEntry.path.at(-1) ?? columnEntry.rawNodeId, responsive);
|
|
3596
|
+
}
|
|
3597
|
+
getSelectedColumnSpan() {
|
|
3598
|
+
const columnEntry = this.getSelectedColumnEntry();
|
|
3599
|
+
const column = columnEntry?.node;
|
|
3600
|
+
if (!column || column.type !== 'col')
|
|
3601
|
+
return null;
|
|
3602
|
+
return this.getEffectiveSpan(column.responsive ?? { xs: LayoutNodeComponent.MAX_COLUMN_SPAN });
|
|
3603
|
+
}
|
|
3604
|
+
getSelectedColumnEntry() {
|
|
3605
|
+
const columnId = this.designerState.selectedColumnId();
|
|
3606
|
+
if (!columnId)
|
|
3607
|
+
return null;
|
|
3608
|
+
return this.designerState.layoutIndex()[columnId] ?? null;
|
|
3609
|
+
}
|
|
3273
3610
|
getColClasses(node) {
|
|
3274
3611
|
if (node.type !== 'col')
|
|
3275
3612
|
return '';
|
|
@@ -3445,6 +3782,9 @@ class LayoutNodeComponent {
|
|
|
3445
3782
|
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3446
3783
|
[class.outline-1]="designMode && showLayoutGuides"
|
|
3447
3784
|
[class.outline-blue-200]="designMode && showLayoutGuides && !isSelected"
|
|
3785
|
+
[class.ring-1]="designMode && isRowSelectionAncestor"
|
|
3786
|
+
[class.ring-emerald-200]="designMode && isRowSelectionAncestor"
|
|
3787
|
+
[class.bg-emerald-50]="designMode && isRowSelectionAncestor"
|
|
3448
3788
|
[class.ring-2]="designMode && isSelected"
|
|
3449
3789
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3450
3790
|
[class.bg-blue-50]="designMode && isSelected">
|
|
@@ -3520,6 +3860,9 @@ class LayoutNodeComponent {
|
|
|
3520
3860
|
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3521
3861
|
[class.outline-1]="designMode && showLayoutGuides"
|
|
3522
3862
|
[class.outline-gray-300]="designMode && showLayoutGuides && !isSelected"
|
|
3863
|
+
[class.ring-1]="designMode && isColumnSelectionAncestor"
|
|
3864
|
+
[class.ring-amber-200]="designMode && isColumnSelectionAncestor"
|
|
3865
|
+
[class.bg-amber-50]="designMode && isColumnSelectionAncestor"
|
|
3523
3866
|
[class.ring-2]="designMode && isSelected"
|
|
3524
3867
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3525
3868
|
[class.bg-blue-50]="designMode && isSelected && asCol(node).children.length === 0">
|
|
@@ -3547,6 +3890,22 @@ class LayoutNodeComponent {
|
|
|
3547
3890
|
<lucide-icon name="layout-list" class="w-3.5 h-3.5"></lucide-icon>
|
|
3548
3891
|
</button>
|
|
3549
3892
|
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
3893
|
+
<button type="button"
|
|
3894
|
+
(click)="decreaseSelectedColumnSpan()"
|
|
3895
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
3896
|
+
title="Decrease width"
|
|
3897
|
+
[disabled]="!canDecreaseSelectedColumnSpan()">
|
|
3898
|
+
-
|
|
3899
|
+
</button>
|
|
3900
|
+
<span class="min-w-10 text-center text-[10px] font-semibold text-gray-300">{{ getSelectedColumnSpanLabel() }}</span>
|
|
3901
|
+
<button type="button"
|
|
3902
|
+
(click)="increaseSelectedColumnSpan()"
|
|
3903
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
3904
|
+
title="Increase width"
|
|
3905
|
+
[disabled]="!canIncreaseSelectedColumnSpan()">
|
|
3906
|
+
+
|
|
3907
|
+
</button>
|
|
3908
|
+
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
3550
3909
|
<span class="text-gray-400 uppercase font-semibold text-[10px] px-1.5">Column</span>
|
|
3551
3910
|
</div>
|
|
3552
3911
|
|
|
@@ -3582,13 +3941,6 @@ class LayoutNodeComponent {
|
|
|
3582
3941
|
<div *cdkDragPlaceholder class="min-h-[50px] bg-blue-50 border-2 border-blue-200 border-dashed mb-2 rounded"></div>
|
|
3583
3942
|
</div>
|
|
3584
3943
|
|
|
3585
|
-
<!-- Placeholder for empty col in designer -->
|
|
3586
|
-
<div *ngIf="asCol(node).children.length === 0 && designMode"
|
|
3587
|
-
class="h-full w-full min-h-[4rem] flex flex-col items-center justify-center p-4 border-2 border-dashed border-gray-200 rounded-lg bg-gray-50/50 hover:bg-gray-100 hover:border-blue-300 transition-all text-gray-400 gap-2">
|
|
3588
|
-
<lucide-icon name="plus" class="w-5 h-5 opacity-50"></lucide-icon>
|
|
3589
|
-
<span class="text-xs font-medium">Drop Widget Here</span>
|
|
3590
|
-
</div>
|
|
3591
|
-
|
|
3592
3944
|
<!-- Resize Handle - z-50 to stay above widget overlays -->
|
|
3593
3945
|
<!-- Width Resize (Right) - Only if not last column in row -->
|
|
3594
3946
|
<div *ngIf="designMode && isSelected"
|
|
@@ -3639,6 +3991,22 @@ class LayoutNodeComponent {
|
|
|
3639
3991
|
<lucide-icon name="group" class="w-3.5 h-3.5"></lucide-icon>
|
|
3640
3992
|
</button>
|
|
3641
3993
|
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
3994
|
+
<button type="button"
|
|
3995
|
+
(click)="decreaseSelectedColumnSpan()"
|
|
3996
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
3997
|
+
title="Decrease width"
|
|
3998
|
+
[disabled]="!canDecreaseSelectedColumnSpan()">
|
|
3999
|
+
-
|
|
4000
|
+
</button>
|
|
4001
|
+
<span class="min-w-10 text-center text-[10px] font-semibold text-gray-300">{{ getSelectedColumnSpanLabel() }}</span>
|
|
4002
|
+
<button type="button"
|
|
4003
|
+
(click)="increaseSelectedColumnSpan()"
|
|
4004
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
4005
|
+
title="Increase width"
|
|
4006
|
+
[disabled]="!canIncreaseSelectedColumnSpan()">
|
|
4007
|
+
+
|
|
4008
|
+
</button>
|
|
4009
|
+
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
3642
4010
|
<span class="text-gray-400 uppercase font-semibold text-[10px] px-1.5">{{ getNodeTypeLabel() }}</span>
|
|
3643
4011
|
</div>
|
|
3644
4012
|
|
|
@@ -3699,6 +4067,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3699
4067
|
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3700
4068
|
[class.outline-1]="designMode && showLayoutGuides"
|
|
3701
4069
|
[class.outline-blue-200]="designMode && showLayoutGuides && !isSelected"
|
|
4070
|
+
[class.ring-1]="designMode && isRowSelectionAncestor"
|
|
4071
|
+
[class.ring-emerald-200]="designMode && isRowSelectionAncestor"
|
|
4072
|
+
[class.bg-emerald-50]="designMode && isRowSelectionAncestor"
|
|
3702
4073
|
[class.ring-2]="designMode && isSelected"
|
|
3703
4074
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3704
4075
|
[class.bg-blue-50]="designMode && isSelected">
|
|
@@ -3774,6 +4145,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3774
4145
|
[class.outline-dashed]="designMode && showLayoutGuides"
|
|
3775
4146
|
[class.outline-1]="designMode && showLayoutGuides"
|
|
3776
4147
|
[class.outline-gray-300]="designMode && showLayoutGuides && !isSelected"
|
|
4148
|
+
[class.ring-1]="designMode && isColumnSelectionAncestor"
|
|
4149
|
+
[class.ring-amber-200]="designMode && isColumnSelectionAncestor"
|
|
4150
|
+
[class.bg-amber-50]="designMode && isColumnSelectionAncestor"
|
|
3777
4151
|
[class.ring-2]="designMode && isSelected"
|
|
3778
4152
|
[class.ring-blue-500]="designMode && isSelected"
|
|
3779
4153
|
[class.bg-blue-50]="designMode && isSelected && asCol(node).children.length === 0">
|
|
@@ -3801,6 +4175,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3801
4175
|
<lucide-icon name="layout-list" class="w-3.5 h-3.5"></lucide-icon>
|
|
3802
4176
|
</button>
|
|
3803
4177
|
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
4178
|
+
<button type="button"
|
|
4179
|
+
(click)="decreaseSelectedColumnSpan()"
|
|
4180
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
4181
|
+
title="Decrease width"
|
|
4182
|
+
[disabled]="!canDecreaseSelectedColumnSpan()">
|
|
4183
|
+
-
|
|
4184
|
+
</button>
|
|
4185
|
+
<span class="min-w-10 text-center text-[10px] font-semibold text-gray-300">{{ getSelectedColumnSpanLabel() }}</span>
|
|
4186
|
+
<button type="button"
|
|
4187
|
+
(click)="increaseSelectedColumnSpan()"
|
|
4188
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
4189
|
+
title="Increase width"
|
|
4190
|
+
[disabled]="!canIncreaseSelectedColumnSpan()">
|
|
4191
|
+
+
|
|
4192
|
+
</button>
|
|
4193
|
+
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
3804
4194
|
<span class="text-gray-400 uppercase font-semibold text-[10px] px-1.5">Column</span>
|
|
3805
4195
|
</div>
|
|
3806
4196
|
|
|
@@ -3836,13 +4226,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3836
4226
|
<div *cdkDragPlaceholder class="min-h-[50px] bg-blue-50 border-2 border-blue-200 border-dashed mb-2 rounded"></div>
|
|
3837
4227
|
</div>
|
|
3838
4228
|
|
|
3839
|
-
<!-- Placeholder for empty col in designer -->
|
|
3840
|
-
<div *ngIf="asCol(node).children.length === 0 && designMode"
|
|
3841
|
-
class="h-full w-full min-h-[4rem] flex flex-col items-center justify-center p-4 border-2 border-dashed border-gray-200 rounded-lg bg-gray-50/50 hover:bg-gray-100 hover:border-blue-300 transition-all text-gray-400 gap-2">
|
|
3842
|
-
<lucide-icon name="plus" class="w-5 h-5 opacity-50"></lucide-icon>
|
|
3843
|
-
<span class="text-xs font-medium">Drop Widget Here</span>
|
|
3844
|
-
</div>
|
|
3845
|
-
|
|
3846
4229
|
<!-- Resize Handle - z-50 to stay above widget overlays -->
|
|
3847
4230
|
<!-- Width Resize (Right) - Only if not last column in row -->
|
|
3848
4231
|
<div *ngIf="designMode && isSelected"
|
|
@@ -3893,6 +4276,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3893
4276
|
<lucide-icon name="group" class="w-3.5 h-3.5"></lucide-icon>
|
|
3894
4277
|
</button>
|
|
3895
4278
|
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
4279
|
+
<button type="button"
|
|
4280
|
+
(click)="decreaseSelectedColumnSpan()"
|
|
4281
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
4282
|
+
title="Decrease width"
|
|
4283
|
+
[disabled]="!canDecreaseSelectedColumnSpan()">
|
|
4284
|
+
-
|
|
4285
|
+
</button>
|
|
4286
|
+
<span class="min-w-10 text-center text-[10px] font-semibold text-gray-300">{{ getSelectedColumnSpanLabel() }}</span>
|
|
4287
|
+
<button type="button"
|
|
4288
|
+
(click)="increaseSelectedColumnSpan()"
|
|
4289
|
+
class="px-2 py-1 hover:bg-gray-700 rounded transition-colors disabled:opacity-40 disabled:hover:bg-transparent"
|
|
4290
|
+
title="Increase width"
|
|
4291
|
+
[disabled]="!canIncreaseSelectedColumnSpan()">
|
|
4292
|
+
+
|
|
4293
|
+
</button>
|
|
4294
|
+
<div class="w-px h-4 bg-gray-700 mx-0.5"></div>
|
|
3896
4295
|
<span class="text-gray-400 uppercase font-semibold text-[10px] px-1.5">{{ getNodeTypeLabel() }}</span>
|
|
3897
4296
|
</div>
|
|
3898
4297
|
|
|
@@ -4864,7 +5263,7 @@ class JsonFormRendererComponent {
|
|
|
4864
5263
|
this.valueChange.emit(fieldValueMap);
|
|
4865
5264
|
this.groupedValueChange.emit(groupedValues);
|
|
4866
5265
|
this.combinedValueChange.emit(combinedValues);
|
|
4867
|
-
this.validationChange.emit(this.getValidationResult());
|
|
5266
|
+
this.validationChange.emit(this.getValidationResult(true));
|
|
4868
5267
|
}
|
|
4869
5268
|
disposeRunner() {
|
|
4870
5269
|
if (this.runner) {
|
|
@@ -5016,11 +5415,7 @@ class JsonFormRendererComponent {
|
|
|
5016
5415
|
event.preventDefault();
|
|
5017
5416
|
if (this.mode === 'design')
|
|
5018
5417
|
return;
|
|
5019
|
-
const
|
|
5020
|
-
const validation = {
|
|
5021
|
-
errors: { ...errors },
|
|
5022
|
-
isValid: Object.keys(errors).length === 0
|
|
5023
|
-
};
|
|
5418
|
+
const validation = this.getValidationResult(true);
|
|
5024
5419
|
this.validationChange.emit(validation);
|
|
5025
5420
|
// Notify all widgets to show errors if any
|
|
5026
5421
|
this.engine?.submit();
|
|
@@ -5042,13 +5437,134 @@ class JsonFormRendererComponent {
|
|
|
5042
5437
|
validation
|
|
5043
5438
|
});
|
|
5044
5439
|
}
|
|
5045
|
-
getValidationResult() {
|
|
5046
|
-
const errors =
|
|
5440
|
+
getValidationResult(revalidate = false) {
|
|
5441
|
+
const errors = revalidate
|
|
5442
|
+
? (this.engine?.validate() ?? {})
|
|
5443
|
+
: (this.engine?.getErrors() ?? {});
|
|
5047
5444
|
return {
|
|
5048
|
-
errors,
|
|
5049
|
-
isValid: Object.keys(errors).length === 0
|
|
5445
|
+
errors: { ...errors },
|
|
5446
|
+
isValid: Object.keys(errors).length === 0,
|
|
5447
|
+
fields: this.buildFieldValidationState(errors)
|
|
5050
5448
|
};
|
|
5051
5449
|
}
|
|
5450
|
+
buildFieldValidationState(errors) {
|
|
5451
|
+
const schema = this.engine?.getSchema() ?? this.schema;
|
|
5452
|
+
if (!schema)
|
|
5453
|
+
return {};
|
|
5454
|
+
const states = {};
|
|
5455
|
+
for (const field of schema.fields) {
|
|
5456
|
+
const visible = this.engine ? this.engine.isFieldVisible(field.id) : true;
|
|
5457
|
+
const required = visible && (this.engine
|
|
5458
|
+
? this.engine.isFieldRequired(field.id)
|
|
5459
|
+
: !!field.html5?.required);
|
|
5460
|
+
const fieldErrors = errors[field.name] ? [...errors[field.name]] : [];
|
|
5461
|
+
states[field.name] = {
|
|
5462
|
+
fieldId: field.id,
|
|
5463
|
+
fieldName: field.name,
|
|
5464
|
+
...(field.label ? { label: field.label } : {}),
|
|
5465
|
+
visible,
|
|
5466
|
+
required,
|
|
5467
|
+
valid: fieldErrors.length === 0,
|
|
5468
|
+
errors: fieldErrors,
|
|
5469
|
+
validators: this.describeFieldValidators(field, visible, required)
|
|
5470
|
+
};
|
|
5471
|
+
}
|
|
5472
|
+
return states;
|
|
5473
|
+
}
|
|
5474
|
+
describeFieldValidators(field, visible, required) {
|
|
5475
|
+
const validators = [];
|
|
5476
|
+
const value = this.engine?.getValue(field.name);
|
|
5477
|
+
const hasValue = !this.isValidationEmpty(value);
|
|
5478
|
+
if (this.hasRequiredValidation(field) || required) {
|
|
5479
|
+
validators.push({
|
|
5480
|
+
name: 'required',
|
|
5481
|
+
source: 'required',
|
|
5482
|
+
active: visible && required,
|
|
5483
|
+
message: 'This field is required.'
|
|
5484
|
+
});
|
|
5485
|
+
}
|
|
5486
|
+
if (field.html5?.minLength !== undefined) {
|
|
5487
|
+
validators.push({
|
|
5488
|
+
name: 'minLength',
|
|
5489
|
+
source: 'html5',
|
|
5490
|
+
active: visible && hasValue,
|
|
5491
|
+
value: field.html5.minLength
|
|
5492
|
+
});
|
|
5493
|
+
}
|
|
5494
|
+
if (field.html5?.maxLength !== undefined) {
|
|
5495
|
+
validators.push({
|
|
5496
|
+
name: 'maxLength',
|
|
5497
|
+
source: 'html5',
|
|
5498
|
+
active: visible && hasValue,
|
|
5499
|
+
value: field.html5.maxLength
|
|
5500
|
+
});
|
|
5501
|
+
}
|
|
5502
|
+
if (field.html5?.min !== undefined) {
|
|
5503
|
+
validators.push({
|
|
5504
|
+
name: 'min',
|
|
5505
|
+
source: 'html5',
|
|
5506
|
+
active: visible && hasValue,
|
|
5507
|
+
value: field.html5.min
|
|
5508
|
+
});
|
|
5509
|
+
}
|
|
5510
|
+
if (field.html5?.max !== undefined) {
|
|
5511
|
+
validators.push({
|
|
5512
|
+
name: 'max',
|
|
5513
|
+
source: 'html5',
|
|
5514
|
+
active: visible && hasValue,
|
|
5515
|
+
value: field.html5.max
|
|
5516
|
+
});
|
|
5517
|
+
}
|
|
5518
|
+
if (field.html5?.pattern) {
|
|
5519
|
+
validators.push({
|
|
5520
|
+
name: 'pattern',
|
|
5521
|
+
source: 'html5',
|
|
5522
|
+
active: visible && hasValue,
|
|
5523
|
+
value: field.html5.pattern
|
|
5524
|
+
});
|
|
5525
|
+
}
|
|
5526
|
+
for (const rule of field.validation ?? []) {
|
|
5527
|
+
validators.push({
|
|
5528
|
+
name: rule.type === 'builtin' ? (rule.name ?? 'builtin') : 'expression',
|
|
5529
|
+
source: 'custom',
|
|
5530
|
+
active: visible && hasValue && this.isValidationRuleActive(rule),
|
|
5531
|
+
value: rule.type === 'expression' ? rule.expression : rule.name,
|
|
5532
|
+
message: rule.message
|
|
5533
|
+
});
|
|
5534
|
+
}
|
|
5535
|
+
return validators;
|
|
5536
|
+
}
|
|
5537
|
+
hasRequiredValidation(field) {
|
|
5538
|
+
if (field.html5?.required)
|
|
5539
|
+
return true;
|
|
5540
|
+
if (field.dependencies?.some(rule => rule.effect === 'require' || rule.effect === 'optional')) {
|
|
5541
|
+
return true;
|
|
5542
|
+
}
|
|
5543
|
+
if (field.rules?.some(rule => rule.action === 'required'
|
|
5544
|
+
|| rule.action === 'optional'
|
|
5545
|
+
|| rule.elseAction === 'required'
|
|
5546
|
+
|| rule.elseAction === 'optional')) {
|
|
5547
|
+
return true;
|
|
5548
|
+
}
|
|
5549
|
+
return false;
|
|
5550
|
+
}
|
|
5551
|
+
isValidationRuleActive(rule) {
|
|
5552
|
+
if (!rule.when)
|
|
5553
|
+
return true;
|
|
5554
|
+
try {
|
|
5555
|
+
const checkFn = new Function('form', `return ${rule.when}`);
|
|
5556
|
+
return checkFn(this.engine?.getValues() ?? {});
|
|
5557
|
+
}
|
|
5558
|
+
catch {
|
|
5559
|
+
return false;
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
isValidationEmpty(value) {
|
|
5563
|
+
return value === null
|
|
5564
|
+
|| value === undefined
|
|
5565
|
+
|| value === ''
|
|
5566
|
+
|| (Array.isArray(value) && value.length === 0);
|
|
5567
|
+
}
|
|
5052
5568
|
async uploadPendingFiles() {
|
|
5053
5569
|
if (!this.engine)
|
|
5054
5570
|
return {};
|
|
@@ -5678,11 +6194,7 @@ class FormJourneyViewerComponent {
|
|
|
5678
6194
|
return { ok: false, reason: 'unknown-page' };
|
|
5679
6195
|
}
|
|
5680
6196
|
if (!this.viewOnly && this.renderer?.engine) {
|
|
5681
|
-
const
|
|
5682
|
-
const validation = {
|
|
5683
|
-
errors: { ...errors },
|
|
5684
|
-
isValid: Object.keys(errors).length === 0
|
|
5685
|
-
};
|
|
6197
|
+
const validation = this.renderer.getValidationResult(true);
|
|
5686
6198
|
this.formValidationChange.emit(validation);
|
|
5687
6199
|
if (!validation.isValid) {
|
|
5688
6200
|
return { ok: false, reason: 'validation' };
|
|
@@ -7684,6 +8196,7 @@ class LayoutCanvasComponent {
|
|
|
7684
8196
|
showLiveSchemaEditor = signal(false);
|
|
7685
8197
|
liveSchemaEditorText = signal('');
|
|
7686
8198
|
liveSchemaEditorError = signal('');
|
|
8199
|
+
openContextSubmenu = signal(null);
|
|
7687
8200
|
liveSchemaEditorOptions = {
|
|
7688
8201
|
fontSize: 12,
|
|
7689
8202
|
lineNumbersMinChars: 3,
|
|
@@ -7801,6 +8314,7 @@ class LayoutCanvasComponent {
|
|
|
7801
8314
|
this.closeContextMenu();
|
|
7802
8315
|
}
|
|
7803
8316
|
closeContextMenu() {
|
|
8317
|
+
this.openContextSubmenu.set(null);
|
|
7804
8318
|
this.state.closeContextMenu();
|
|
7805
8319
|
}
|
|
7806
8320
|
groupSelected() {
|
|
@@ -7811,6 +8325,46 @@ class LayoutCanvasComponent {
|
|
|
7811
8325
|
this.state.ungroupSelectedFields();
|
|
7812
8326
|
this.closeContextMenu();
|
|
7813
8327
|
}
|
|
8328
|
+
hasStructuralInsertActions() {
|
|
8329
|
+
return this.state.canInsertColumnBeforeSelection()
|
|
8330
|
+
|| this.state.canInsertColumnAfterSelection()
|
|
8331
|
+
|| this.state.canInsertRowInSelectedColumn()
|
|
8332
|
+
|| this.state.canInsertRowBeforeSelection()
|
|
8333
|
+
|| this.state.canInsertRowAfterSelection()
|
|
8334
|
+
|| this.state.canArmFieldInsertBeforeSelection()
|
|
8335
|
+
|| this.state.canArmFieldInsertAfterSelection();
|
|
8336
|
+
}
|
|
8337
|
+
toggleInsertSubmenu() {
|
|
8338
|
+
this.openContextSubmenu.update(current => current === 'insert' ? null : 'insert');
|
|
8339
|
+
}
|
|
8340
|
+
insertColumnBeforeSelection() {
|
|
8341
|
+
this.state.insertColumnBeforeSelection();
|
|
8342
|
+
this.closeContextMenu();
|
|
8343
|
+
}
|
|
8344
|
+
insertColumnAfterSelection() {
|
|
8345
|
+
this.state.insertColumnAfterSelection();
|
|
8346
|
+
this.closeContextMenu();
|
|
8347
|
+
}
|
|
8348
|
+
insertRowInSelectedColumn() {
|
|
8349
|
+
this.state.insertRowInSelectedColumn();
|
|
8350
|
+
this.closeContextMenu();
|
|
8351
|
+
}
|
|
8352
|
+
insertRowBeforeSelection() {
|
|
8353
|
+
this.state.insertRowBeforeSelection();
|
|
8354
|
+
this.closeContextMenu();
|
|
8355
|
+
}
|
|
8356
|
+
insertRowAfterSelection() {
|
|
8357
|
+
this.state.insertRowAfterSelection();
|
|
8358
|
+
this.closeContextMenu();
|
|
8359
|
+
}
|
|
8360
|
+
armFieldInsertBeforeSelection() {
|
|
8361
|
+
this.state.armFieldInsertBeforeSelection();
|
|
8362
|
+
this.closeContextMenu();
|
|
8363
|
+
}
|
|
8364
|
+
armFieldInsertAfterSelection() {
|
|
8365
|
+
this.state.armFieldInsertAfterSelection();
|
|
8366
|
+
this.closeContextMenu();
|
|
8367
|
+
}
|
|
7814
8368
|
onCanvasContextMenu(event) {
|
|
7815
8369
|
event.preventDefault();
|
|
7816
8370
|
event.stopPropagation();
|
|
@@ -8249,6 +8803,56 @@ class LayoutCanvasComponent {
|
|
|
8249
8803
|
<span>Delete</span>
|
|
8250
8804
|
<span class="opacity-60 text-[10px]">Del</span>
|
|
8251
8805
|
</button>
|
|
8806
|
+
<div *ngIf="hasStructuralInsertActions()" class="relative">
|
|
8807
|
+
<div class="h-px bg-border-default my-1"></div>
|
|
8808
|
+
<button type="button"
|
|
8809
|
+
aria-label="Open insert submenu"
|
|
8810
|
+
class="flex w-full items-center justify-between px-3 py-2 text-left text-text-primary hover:bg-slate-50"
|
|
8811
|
+
[attr.aria-expanded]="openContextSubmenu() === 'insert'"
|
|
8812
|
+
(click)="toggleInsertSubmenu(); $event.stopPropagation()">
|
|
8813
|
+
<span>Insert…</span>
|
|
8814
|
+
<span class="text-[10px] opacity-60">{{ openContextSubmenu() === 'insert' ? '‹' : '›' }}</span>
|
|
8815
|
+
</button>
|
|
8816
|
+
|
|
8817
|
+
<div *ngIf="openContextSubmenu() === 'insert'"
|
|
8818
|
+
class="absolute left-full top-0 ml-1 min-w-[210px] rounded-md border border-border-default bg-surface-default shadow-popover text-[12px]">
|
|
8819
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertColumnBeforeSelection()" type="button"
|
|
8820
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8821
|
+
(click)="insertColumnBeforeSelection()">
|
|
8822
|
+
Add column left
|
|
8823
|
+
</button>
|
|
8824
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertColumnAfterSelection()" type="button"
|
|
8825
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8826
|
+
(click)="insertColumnAfterSelection()">
|
|
8827
|
+
Add column right
|
|
8828
|
+
</button>
|
|
8829
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertRowInSelectedColumn()" type="button"
|
|
8830
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8831
|
+
(click)="insertRowInSelectedColumn()">
|
|
8832
|
+
Add row in column
|
|
8833
|
+
</button>
|
|
8834
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertRowBeforeSelection()" type="button"
|
|
8835
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8836
|
+
(click)="insertRowBeforeSelection()">
|
|
8837
|
+
Add row above
|
|
8838
|
+
</button>
|
|
8839
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertRowAfterSelection()" type="button"
|
|
8840
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8841
|
+
(click)="insertRowAfterSelection()">
|
|
8842
|
+
Add row below
|
|
8843
|
+
</button>
|
|
8844
|
+
<button *ngIf="!state.isReadOnly() && state.canArmFieldInsertBeforeSelection()" type="button"
|
|
8845
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8846
|
+
(click)="armFieldInsertBeforeSelection()">
|
|
8847
|
+
Next widget above
|
|
8848
|
+
</button>
|
|
8849
|
+
<button *ngIf="!state.isReadOnly() && state.canArmFieldInsertAfterSelection()" type="button"
|
|
8850
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
8851
|
+
(click)="armFieldInsertAfterSelection()">
|
|
8852
|
+
Next widget below
|
|
8853
|
+
</button>
|
|
8854
|
+
</div>
|
|
8855
|
+
</div>
|
|
8252
8856
|
<div class="h-px bg-border-default my-1"></div>
|
|
8253
8857
|
<button *ngIf="!state.isReadOnly()" type="button"
|
|
8254
8858
|
class="w-full px-3 py-2 text-left hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed text-text-primary"
|
|
@@ -8495,6 +9099,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
8495
9099
|
<span>Delete</span>
|
|
8496
9100
|
<span class="opacity-60 text-[10px]">Del</span>
|
|
8497
9101
|
</button>
|
|
9102
|
+
<div *ngIf="hasStructuralInsertActions()" class="relative">
|
|
9103
|
+
<div class="h-px bg-border-default my-1"></div>
|
|
9104
|
+
<button type="button"
|
|
9105
|
+
aria-label="Open insert submenu"
|
|
9106
|
+
class="flex w-full items-center justify-between px-3 py-2 text-left text-text-primary hover:bg-slate-50"
|
|
9107
|
+
[attr.aria-expanded]="openContextSubmenu() === 'insert'"
|
|
9108
|
+
(click)="toggleInsertSubmenu(); $event.stopPropagation()">
|
|
9109
|
+
<span>Insert…</span>
|
|
9110
|
+
<span class="text-[10px] opacity-60">{{ openContextSubmenu() === 'insert' ? '‹' : '›' }}</span>
|
|
9111
|
+
</button>
|
|
9112
|
+
|
|
9113
|
+
<div *ngIf="openContextSubmenu() === 'insert'"
|
|
9114
|
+
class="absolute left-full top-0 ml-1 min-w-[210px] rounded-md border border-border-default bg-surface-default shadow-popover text-[12px]">
|
|
9115
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertColumnBeforeSelection()" type="button"
|
|
9116
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9117
|
+
(click)="insertColumnBeforeSelection()">
|
|
9118
|
+
Add column left
|
|
9119
|
+
</button>
|
|
9120
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertColumnAfterSelection()" type="button"
|
|
9121
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9122
|
+
(click)="insertColumnAfterSelection()">
|
|
9123
|
+
Add column right
|
|
9124
|
+
</button>
|
|
9125
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertRowInSelectedColumn()" type="button"
|
|
9126
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9127
|
+
(click)="insertRowInSelectedColumn()">
|
|
9128
|
+
Add row in column
|
|
9129
|
+
</button>
|
|
9130
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertRowBeforeSelection()" type="button"
|
|
9131
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9132
|
+
(click)="insertRowBeforeSelection()">
|
|
9133
|
+
Add row above
|
|
9134
|
+
</button>
|
|
9135
|
+
<button *ngIf="!state.isReadOnly() && state.canInsertRowAfterSelection()" type="button"
|
|
9136
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9137
|
+
(click)="insertRowAfterSelection()">
|
|
9138
|
+
Add row below
|
|
9139
|
+
</button>
|
|
9140
|
+
<button *ngIf="!state.isReadOnly() && state.canArmFieldInsertBeforeSelection()" type="button"
|
|
9141
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9142
|
+
(click)="armFieldInsertBeforeSelection()">
|
|
9143
|
+
Next widget above
|
|
9144
|
+
</button>
|
|
9145
|
+
<button *ngIf="!state.isReadOnly() && state.canArmFieldInsertAfterSelection()" type="button"
|
|
9146
|
+
class="w-full px-3 py-2 text-left hover:bg-slate-50 text-text-primary"
|
|
9147
|
+
(click)="armFieldInsertAfterSelection()">
|
|
9148
|
+
Next widget below
|
|
9149
|
+
</button>
|
|
9150
|
+
</div>
|
|
9151
|
+
</div>
|
|
8498
9152
|
<div class="h-px bg-border-default my-1"></div>
|
|
8499
9153
|
<button *ngIf="!state.isReadOnly()" type="button"
|
|
8500
9154
|
class="w-full px-3 py-2 text-left hover:bg-slate-50 disabled:opacity-40 disabled:cursor-not-allowed text-text-primary"
|
|
@@ -9606,18 +10260,11 @@ class DynamicPropertiesComponent {
|
|
|
9606
10260
|
onPropertyChange;
|
|
9607
10261
|
designerCtx = inject(DesignerContext);
|
|
9608
10262
|
validatorTypeOptions = [
|
|
9609
|
-
{ label: '
|
|
9610
|
-
{ label: '
|
|
9611
|
-
{ label: 'Min Value', value: 'min' },
|
|
9612
|
-
{ label: 'Max Value', value: 'max' },
|
|
9613
|
-
{ label: 'Min Length', value: 'minLength' },
|
|
9614
|
-
{ label: 'Max Length', value: 'maxLength' },
|
|
9615
|
-
{ label: 'Pattern', value: 'pattern' }
|
|
10263
|
+
{ label: 'Built-in', value: 'builtin' },
|
|
10264
|
+
{ label: 'Expression', value: 'expression' }
|
|
9616
10265
|
];
|
|
9617
|
-
|
|
9618
|
-
{ label: '
|
|
9619
|
-
{ label: 'Field Equals', value: 'equals' },
|
|
9620
|
-
{ label: 'Field Not Equals', value: 'notEquals' }
|
|
10266
|
+
builtinValidatorOptions = [
|
|
10267
|
+
{ label: 'Email', value: 'email' }
|
|
9621
10268
|
];
|
|
9622
10269
|
get properties() {
|
|
9623
10270
|
if (!this.config)
|
|
@@ -9954,18 +10601,15 @@ class DynamicPropertiesComponent {
|
|
|
9954
10601
|
addValidator(path) {
|
|
9955
10602
|
if (this.readOnly)
|
|
9956
10603
|
return;
|
|
9957
|
-
const validators = this.getValue(path) || [];
|
|
9958
|
-
validators.push(
|
|
9959
|
-
name: 'required',
|
|
9960
|
-
message: 'This field is required'
|
|
9961
|
-
});
|
|
10604
|
+
const validators = [...(this.getValue(path) || [])];
|
|
10605
|
+
validators.push(this.createDefaultValidationRule());
|
|
9962
10606
|
this.setValue(path, validators);
|
|
9963
10607
|
this.handleFieldChange();
|
|
9964
10608
|
}
|
|
9965
10609
|
removeValidator(path, index) {
|
|
9966
10610
|
if (this.readOnly)
|
|
9967
10611
|
return;
|
|
9968
|
-
const validators = this.getValue(path) || [];
|
|
10612
|
+
const validators = [...(this.getValue(path) || [])];
|
|
9969
10613
|
validators.splice(index, 1);
|
|
9970
10614
|
this.setValue(path, validators);
|
|
9971
10615
|
this.handleFieldChange();
|
|
@@ -9973,57 +10617,47 @@ class DynamicPropertiesComponent {
|
|
|
9973
10617
|
updateValidator(path, index, field, value) {
|
|
9974
10618
|
if (this.readOnly)
|
|
9975
10619
|
return;
|
|
9976
|
-
const validators = this.getValue(path) || [];
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
if (field === 'name') {
|
|
9981
|
-
const messages = {
|
|
9982
|
-
required: 'This field is required',
|
|
9983
|
-
min: 'Value is too small',
|
|
9984
|
-
max: 'Value is too large',
|
|
9985
|
-
minLength: 'Too short',
|
|
9986
|
-
maxLength: 'Too long',
|
|
9987
|
-
pattern: 'Invalid format',
|
|
9988
|
-
email: 'Invalid email'
|
|
9989
|
-
};
|
|
9990
|
-
validators[index].message = messages[value] || 'Invalid value';
|
|
9991
|
-
}
|
|
9992
|
-
this.setValue(path, validators);
|
|
10620
|
+
const validators = [...(this.getValue(path) || [])];
|
|
10621
|
+
const currentRule = validators[index];
|
|
10622
|
+
if (!currentRule) {
|
|
10623
|
+
return;
|
|
9993
10624
|
}
|
|
10625
|
+
let nextRule = { ...currentRule };
|
|
10626
|
+
if (field === 'type') {
|
|
10627
|
+
nextRule = value === 'expression'
|
|
10628
|
+
? {
|
|
10629
|
+
type: 'expression',
|
|
10630
|
+
expression: 'return true;',
|
|
10631
|
+
message: 'Validation failed.'
|
|
10632
|
+
}
|
|
10633
|
+
: this.createDefaultValidationRule();
|
|
10634
|
+
}
|
|
10635
|
+
else if (field === 'name') {
|
|
10636
|
+
nextRule.name = String(value);
|
|
10637
|
+
nextRule.message = this.defaultValidationMessage(nextRule);
|
|
10638
|
+
}
|
|
10639
|
+
else if (field === 'expression') {
|
|
10640
|
+
nextRule.expression = String(value);
|
|
10641
|
+
}
|
|
10642
|
+
else if (field === 'message') {
|
|
10643
|
+
nextRule.message = String(value);
|
|
10644
|
+
}
|
|
10645
|
+
validators[index] = nextRule;
|
|
10646
|
+
this.setValue(path, validators);
|
|
10647
|
+
this.handleFieldChange();
|
|
9994
10648
|
}
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
minLength: 'Min Length',
|
|
10001
|
-
maxLength: 'Max Length',
|
|
10002
|
-
pattern: 'Regex Pattern',
|
|
10003
|
-
email: 'Email Address'
|
|
10649
|
+
createDefaultValidationRule() {
|
|
10650
|
+
return {
|
|
10651
|
+
type: 'builtin',
|
|
10652
|
+
name: 'email',
|
|
10653
|
+
message: 'Enter a valid email address.'
|
|
10004
10654
|
};
|
|
10005
|
-
return labels[name] || name;
|
|
10006
10655
|
}
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
action: 'visible',
|
|
10013
|
-
operator: 'eq'
|
|
10014
|
-
});
|
|
10015
|
-
}
|
|
10016
|
-
disableConditional(path) {
|
|
10017
|
-
if (this.readOnly)
|
|
10018
|
-
return;
|
|
10019
|
-
this.setValue(path, null);
|
|
10020
|
-
}
|
|
10021
|
-
updateConditional(path, field, value) {
|
|
10022
|
-
if (this.readOnly)
|
|
10023
|
-
return;
|
|
10024
|
-
const condition = this.getValue(path) || {};
|
|
10025
|
-
condition[field] = value;
|
|
10026
|
-
this.setValue(path, condition);
|
|
10656
|
+
defaultValidationMessage(rule) {
|
|
10657
|
+
if (rule.type === 'builtin' && rule.name === 'email') {
|
|
10658
|
+
return 'Enter a valid email address.';
|
|
10659
|
+
}
|
|
10660
|
+
return 'Validation failed.';
|
|
10027
10661
|
}
|
|
10028
10662
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DynamicPropertiesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10029
10663
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: DynamicPropertiesComponent, isStandalone: true, selector: "app-dynamic-properties", inputs: { onPropertyChange: "onPropertyChange", config: "config", readOnly: "readOnly", includeSections: "includeSections", excludeSections: "excludeSections", allFields: "allFields" }, outputs: { configChange: "configChange" }, usesOnChanges: true, ngImport: i0, template: `
|
|
@@ -10180,16 +10814,27 @@ class DynamicPropertiesComponent {
|
|
|
10180
10814
|
</div>
|
|
10181
10815
|
<div class="space-y-2">
|
|
10182
10816
|
<div *ngFor="let val of getValue(field.key) || []; let i = index" class="flex items-center gap-2 p-2 bg-white rounded border border-gray-200">
|
|
10183
|
-
<select [
|
|
10184
|
-
(ngModelChange)="
|
|
10817
|
+
<select [ngModel]="val.type || 'builtin'"
|
|
10818
|
+
(ngModelChange)="updateValidator(field.key, i, 'type', $event)"
|
|
10185
10819
|
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10186
10820
|
<option *ngFor="let option of validatorTypeOptions" [value]="option.value">{{ option.label }}</option>
|
|
10187
10821
|
</select>
|
|
10188
|
-
<
|
|
10822
|
+
<select *ngIf="(val.type || 'builtin') === 'builtin'"
|
|
10823
|
+
[ngModel]="val.name || 'email'"
|
|
10824
|
+
(ngModelChange)="updateValidator(field.key, i, 'name', $event)"
|
|
10825
|
+
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10826
|
+
<option *ngFor="let option of builtinValidatorOptions" [value]="option.value">{{ option.label }}</option>
|
|
10827
|
+
</select>
|
|
10828
|
+
<input *ngIf="val.type === 'expression'"
|
|
10189
10829
|
type="text"
|
|
10190
|
-
[
|
|
10191
|
-
(
|
|
10192
|
-
placeholder="
|
|
10830
|
+
[ngModel]="val.expression || ''"
|
|
10831
|
+
(ngModelChange)="updateValidator(field.key, i, 'expression', $event)"
|
|
10832
|
+
placeholder="return true;"
|
|
10833
|
+
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10834
|
+
<input type="text"
|
|
10835
|
+
[ngModel]="val.message || ''"
|
|
10836
|
+
(ngModelChange)="updateValidator(field.key, i, 'message', $event)"
|
|
10837
|
+
placeholder="Validation message"
|
|
10193
10838
|
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10194
10839
|
<button type="button"
|
|
10195
10840
|
(click)="removeValidator(field.key, i)"
|
|
@@ -10201,36 +10846,6 @@ class DynamicPropertiesComponent {
|
|
|
10201
10846
|
</div>
|
|
10202
10847
|
</ui-field-wrapper>
|
|
10203
10848
|
|
|
10204
|
-
<!-- Conditional Editor -->
|
|
10205
|
-
<ui-field-wrapper *ngIf="field.type === 'conditional-editor'" [label]="field.label || ''" [helpText]="field.helpText || ''">
|
|
10206
|
-
<div class="w-full border border-gray-200 rounded-lg p-3 bg-gray-50">
|
|
10207
|
-
<div class="flex flex-col gap-2">
|
|
10208
|
-
<select [ngModel]="getValue(field.key + '.type')"
|
|
10209
|
-
(ngModelChange)="setValue(field.key + '.type', $event); handleFieldChange()"
|
|
10210
|
-
class="h-8 w-full rounded border border-gray-300 bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10211
|
-
<option *ngFor="let option of conditionalTypeOptions" [value]="option.value">{{ option.label }}</option>
|
|
10212
|
-
</select>
|
|
10213
|
-
<div *ngIf="getValue(field.key + '.type') !== 'always'" class="flex gap-2">
|
|
10214
|
-
<input type="text"
|
|
10215
|
-
[ngModel]="getValue(field.key + '.field')"
|
|
10216
|
-
(ngModelChange)="setValue(field.key + '.field', $event)"
|
|
10217
|
-
(blur)="handleFieldChange()"
|
|
10218
|
-
placeholder="Field Name"
|
|
10219
|
-
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10220
|
-
<input type="text"
|
|
10221
|
-
[ngModel]="getValue(field.key + '.value')"
|
|
10222
|
-
(ngModelChange)="setValue(field.key + '.value', $event)"
|
|
10223
|
-
(blur)="handleFieldChange()"
|
|
10224
|
-
placeholder="Value"
|
|
10225
|
-
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10226
|
-
</div>
|
|
10227
|
-
</div>
|
|
10228
|
-
<div *ngIf="getValue(field.key + '.type') === 'always'" class="text-xs text-gray-400 mt-2">
|
|
10229
|
-
Field always visible.
|
|
10230
|
-
</div>
|
|
10231
|
-
</div>
|
|
10232
|
-
</ui-field-wrapper>
|
|
10233
|
-
|
|
10234
10849
|
<!-- Field Reference -->
|
|
10235
10850
|
<ui-field-wrapper *ngIf="field.type === 'field-reference'" [label]="field.label || ''" [helpText]="field.helpText || ''">
|
|
10236
10851
|
<select [ngModel]="getValue(field.key) || ''"
|
|
@@ -10492,16 +11107,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
10492
11107
|
</div>
|
|
10493
11108
|
<div class="space-y-2">
|
|
10494
11109
|
<div *ngFor="let val of getValue(field.key) || []; let i = index" class="flex items-center gap-2 p-2 bg-white rounded border border-gray-200">
|
|
10495
|
-
<select [
|
|
10496
|
-
(ngModelChange)="
|
|
11110
|
+
<select [ngModel]="val.type || 'builtin'"
|
|
11111
|
+
(ngModelChange)="updateValidator(field.key, i, 'type', $event)"
|
|
10497
11112
|
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10498
11113
|
<option *ngFor="let option of validatorTypeOptions" [value]="option.value">{{ option.label }}</option>
|
|
10499
11114
|
</select>
|
|
10500
|
-
<
|
|
11115
|
+
<select *ngIf="(val.type || 'builtin') === 'builtin'"
|
|
11116
|
+
[ngModel]="val.name || 'email'"
|
|
11117
|
+
(ngModelChange)="updateValidator(field.key, i, 'name', $event)"
|
|
11118
|
+
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
11119
|
+
<option *ngFor="let option of builtinValidatorOptions" [value]="option.value">{{ option.label }}</option>
|
|
11120
|
+
</select>
|
|
11121
|
+
<input *ngIf="val.type === 'expression'"
|
|
10501
11122
|
type="text"
|
|
10502
|
-
[
|
|
10503
|
-
(
|
|
10504
|
-
placeholder="
|
|
11123
|
+
[ngModel]="val.expression || ''"
|
|
11124
|
+
(ngModelChange)="updateValidator(field.key, i, 'expression', $event)"
|
|
11125
|
+
placeholder="return true;"
|
|
11126
|
+
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
11127
|
+
<input type="text"
|
|
11128
|
+
[ngModel]="val.message || ''"
|
|
11129
|
+
(ngModelChange)="updateValidator(field.key, i, 'message', $event)"
|
|
11130
|
+
placeholder="Validation message"
|
|
10505
11131
|
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10506
11132
|
<button type="button"
|
|
10507
11133
|
(click)="removeValidator(field.key, i)"
|
|
@@ -10513,36 +11139,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
10513
11139
|
</div>
|
|
10514
11140
|
</ui-field-wrapper>
|
|
10515
11141
|
|
|
10516
|
-
<!-- Conditional Editor -->
|
|
10517
|
-
<ui-field-wrapper *ngIf="field.type === 'conditional-editor'" [label]="field.label || ''" [helpText]="field.helpText || ''">
|
|
10518
|
-
<div class="w-full border border-gray-200 rounded-lg p-3 bg-gray-50">
|
|
10519
|
-
<div class="flex flex-col gap-2">
|
|
10520
|
-
<select [ngModel]="getValue(field.key + '.type')"
|
|
10521
|
-
(ngModelChange)="setValue(field.key + '.type', $event); handleFieldChange()"
|
|
10522
|
-
class="h-8 w-full rounded border border-gray-300 bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10523
|
-
<option *ngFor="let option of conditionalTypeOptions" [value]="option.value">{{ option.label }}</option>
|
|
10524
|
-
</select>
|
|
10525
|
-
<div *ngIf="getValue(field.key + '.type') !== 'always'" class="flex gap-2">
|
|
10526
|
-
<input type="text"
|
|
10527
|
-
[ngModel]="getValue(field.key + '.field')"
|
|
10528
|
-
(ngModelChange)="setValue(field.key + '.field', $event)"
|
|
10529
|
-
(blur)="handleFieldChange()"
|
|
10530
|
-
placeholder="Field Name"
|
|
10531
|
-
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10532
|
-
<input type="text"
|
|
10533
|
-
[ngModel]="getValue(field.key + '.value')"
|
|
10534
|
-
(ngModelChange)="setValue(field.key + '.value', $event)"
|
|
10535
|
-
(blur)="handleFieldChange()"
|
|
10536
|
-
placeholder="Value"
|
|
10537
|
-
class="flex-1 h-8 px-2 text-sm rounded border border-gray-300 bg-white focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
10538
|
-
</div>
|
|
10539
|
-
</div>
|
|
10540
|
-
<div *ngIf="getValue(field.key + '.type') === 'always'" class="text-xs text-gray-400 mt-2">
|
|
10541
|
-
Field always visible.
|
|
10542
|
-
</div>
|
|
10543
|
-
</div>
|
|
10544
|
-
</ui-field-wrapper>
|
|
10545
|
-
|
|
10546
11142
|
<!-- Field Reference -->
|
|
10547
11143
|
<ui-field-wrapper *ngIf="field.type === 'field-reference'" [label]="field.label || ''" [helpText]="field.helpText || ''">
|
|
10548
11144
|
<select [ngModel]="getValue(field.key) || ''"
|
|
@@ -13616,6 +14212,161 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
13616
14212
|
`, styles: [".inspector-input{height:1.75rem;padding-left:.5rem;padding-right:.5rem;font-size:.75rem;line-height:1rem;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);color:var(--color-ink-700)}.inspector-input:focus{outline:none;border-color:var(--color-primary-blue)}.inspector-input-with-unit{display:flex;align-items:center;background-color:var(--color-input-dark);border:1px solid var(--color-border-dark);border-radius:var(--radius-md);overflow:hidden}.inspector-number-input{height:1.5rem;padding-left:.5rem;padding-right:.5rem;background-color:transparent;border:none;font-size:.75rem;line-height:1rem;color:var(--color-ink-700)}.inspector-number-input:focus{outline:none}.inspector-unit{font-size:10px;color:var(--color-ink-400);padding-left:.25rem;padding-right:.25rem;background-color:var(--color-input-dark);height:1.5rem;display:flex;align-items:center;border-left:1px solid var(--color-border-dark)}\n"] }]
|
|
13617
14213
|
}] });
|
|
13618
14214
|
|
|
14215
|
+
class InspectorTransformSectionComponent {
|
|
14216
|
+
style = input({});
|
|
14217
|
+
styleChange = output();
|
|
14218
|
+
numberValue(key, fallback) {
|
|
14219
|
+
const value = this.style()?.[key];
|
|
14220
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
14221
|
+
return value;
|
|
14222
|
+
}
|
|
14223
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
14224
|
+
const parsed = Number(value);
|
|
14225
|
+
if (Number.isFinite(parsed)) {
|
|
14226
|
+
return parsed;
|
|
14227
|
+
}
|
|
14228
|
+
}
|
|
14229
|
+
return fallback;
|
|
14230
|
+
}
|
|
14231
|
+
updateTransform(key, value) {
|
|
14232
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
14233
|
+
if (!Number.isFinite(parsed)) {
|
|
14234
|
+
return;
|
|
14235
|
+
}
|
|
14236
|
+
this.styleChange.emit({
|
|
14237
|
+
...(this.style() ?? {}),
|
|
14238
|
+
[key]: parsed
|
|
14239
|
+
});
|
|
14240
|
+
}
|
|
14241
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InspectorTransformSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14242
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: InspectorTransformSectionComponent, isStandalone: true, selector: "inspector-transform-section", inputs: { style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { styleChange: "styleChange" }, ngImport: i0, template: `
|
|
14243
|
+
<div class="flex flex-col gap-3">
|
|
14244
|
+
<ui-range-number
|
|
14245
|
+
label="Translate X"
|
|
14246
|
+
prefix="X"
|
|
14247
|
+
hint="px"
|
|
14248
|
+
helpText="Move the widget horizontally."
|
|
14249
|
+
[min]="-200"
|
|
14250
|
+
[max]="200"
|
|
14251
|
+
[step]="1"
|
|
14252
|
+
[value]="numberValue('transformX', 0)"
|
|
14253
|
+
(valueChange)="updateTransform('transformX', $event)">
|
|
14254
|
+
</ui-range-number>
|
|
14255
|
+
|
|
14256
|
+
<ui-range-number
|
|
14257
|
+
label="Translate Y"
|
|
14258
|
+
prefix="Y"
|
|
14259
|
+
hint="px"
|
|
14260
|
+
helpText="Move the widget vertically."
|
|
14261
|
+
[min]="-200"
|
|
14262
|
+
[max]="200"
|
|
14263
|
+
[step]="1"
|
|
14264
|
+
[value]="numberValue('transformY', 0)"
|
|
14265
|
+
(valueChange)="updateTransform('transformY', $event)">
|
|
14266
|
+
</ui-range-number>
|
|
14267
|
+
|
|
14268
|
+
<ui-range-number
|
|
14269
|
+
label="Translate Z"
|
|
14270
|
+
prefix="Z"
|
|
14271
|
+
hint="px"
|
|
14272
|
+
helpText="Move the widget on the z-axis for 3D transforms."
|
|
14273
|
+
[min]="-200"
|
|
14274
|
+
[max]="200"
|
|
14275
|
+
[step]="1"
|
|
14276
|
+
[value]="numberValue('transformZ', 0)"
|
|
14277
|
+
(valueChange)="updateTransform('transformZ', $event)">
|
|
14278
|
+
</ui-range-number>
|
|
14279
|
+
|
|
14280
|
+
<ui-input
|
|
14281
|
+
label="Rotate"
|
|
14282
|
+
hint="deg"
|
|
14283
|
+
helpText="Rotate the widget in degrees."
|
|
14284
|
+
type="number"
|
|
14285
|
+
[step]="1"
|
|
14286
|
+
[model]="numberValue('rotate', 0)"
|
|
14287
|
+
(modelChange)="updateTransform('rotate', $event)">
|
|
14288
|
+
</ui-input>
|
|
14289
|
+
|
|
14290
|
+
<ui-input
|
|
14291
|
+
label="Scale"
|
|
14292
|
+
helpText="Scale the widget uniformly."
|
|
14293
|
+
type="number"
|
|
14294
|
+
[min]="0"
|
|
14295
|
+
[step]="0.1"
|
|
14296
|
+
[model]="numberValue('scale', 1)"
|
|
14297
|
+
(modelChange)="updateTransform('scale', $event)">
|
|
14298
|
+
</ui-input>
|
|
14299
|
+
</div>
|
|
14300
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiInputComponent, selector: "ui-input", inputs: ["label", "hint", "helpText", "placeholder", "type", "min", "max", "step", "model"], outputs: ["modelChange", "onBlur"] }, { kind: "component", type: UiRangeNumberComponent, selector: "ui-range-number", inputs: ["label", "hint", "helpText", "prefix", "min", "max", "step", "value"], outputs: ["valueChange"] }] });
|
|
14301
|
+
}
|
|
14302
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InspectorTransformSectionComponent, decorators: [{
|
|
14303
|
+
type: Component,
|
|
14304
|
+
args: [{
|
|
14305
|
+
selector: 'inspector-transform-section',
|
|
14306
|
+
standalone: true,
|
|
14307
|
+
imports: [CommonModule, UiInputComponent, UiRangeNumberComponent],
|
|
14308
|
+
template: `
|
|
14309
|
+
<div class="flex flex-col gap-3">
|
|
14310
|
+
<ui-range-number
|
|
14311
|
+
label="Translate X"
|
|
14312
|
+
prefix="X"
|
|
14313
|
+
hint="px"
|
|
14314
|
+
helpText="Move the widget horizontally."
|
|
14315
|
+
[min]="-200"
|
|
14316
|
+
[max]="200"
|
|
14317
|
+
[step]="1"
|
|
14318
|
+
[value]="numberValue('transformX', 0)"
|
|
14319
|
+
(valueChange)="updateTransform('transformX', $event)">
|
|
14320
|
+
</ui-range-number>
|
|
14321
|
+
|
|
14322
|
+
<ui-range-number
|
|
14323
|
+
label="Translate Y"
|
|
14324
|
+
prefix="Y"
|
|
14325
|
+
hint="px"
|
|
14326
|
+
helpText="Move the widget vertically."
|
|
14327
|
+
[min]="-200"
|
|
14328
|
+
[max]="200"
|
|
14329
|
+
[step]="1"
|
|
14330
|
+
[value]="numberValue('transformY', 0)"
|
|
14331
|
+
(valueChange)="updateTransform('transformY', $event)">
|
|
14332
|
+
</ui-range-number>
|
|
14333
|
+
|
|
14334
|
+
<ui-range-number
|
|
14335
|
+
label="Translate Z"
|
|
14336
|
+
prefix="Z"
|
|
14337
|
+
hint="px"
|
|
14338
|
+
helpText="Move the widget on the z-axis for 3D transforms."
|
|
14339
|
+
[min]="-200"
|
|
14340
|
+
[max]="200"
|
|
14341
|
+
[step]="1"
|
|
14342
|
+
[value]="numberValue('transformZ', 0)"
|
|
14343
|
+
(valueChange)="updateTransform('transformZ', $event)">
|
|
14344
|
+
</ui-range-number>
|
|
14345
|
+
|
|
14346
|
+
<ui-input
|
|
14347
|
+
label="Rotate"
|
|
14348
|
+
hint="deg"
|
|
14349
|
+
helpText="Rotate the widget in degrees."
|
|
14350
|
+
type="number"
|
|
14351
|
+
[step]="1"
|
|
14352
|
+
[model]="numberValue('rotate', 0)"
|
|
14353
|
+
(modelChange)="updateTransform('rotate', $event)">
|
|
14354
|
+
</ui-input>
|
|
14355
|
+
|
|
14356
|
+
<ui-input
|
|
14357
|
+
label="Scale"
|
|
14358
|
+
helpText="Scale the widget uniformly."
|
|
14359
|
+
type="number"
|
|
14360
|
+
[min]="0"
|
|
14361
|
+
[step]="0.1"
|
|
14362
|
+
[model]="numberValue('scale', 1)"
|
|
14363
|
+
(modelChange)="updateTransform('scale', $event)">
|
|
14364
|
+
</ui-input>
|
|
14365
|
+
</div>
|
|
14366
|
+
`
|
|
14367
|
+
}]
|
|
14368
|
+
}] });
|
|
14369
|
+
|
|
13619
14370
|
const DEDICATED_STYLE_KEYS = new Set([
|
|
13620
14371
|
'alignItems',
|
|
13621
14372
|
'alignSelf',
|
|
@@ -13684,7 +14435,13 @@ const DEDICATED_STYLE_KEYS = new Set([
|
|
|
13684
14435
|
'right',
|
|
13685
14436
|
'textAlign',
|
|
13686
14437
|
'textDecoration',
|
|
14438
|
+
'transform',
|
|
14439
|
+
'transformX',
|
|
14440
|
+
'transformY',
|
|
14441
|
+
'transformZ',
|
|
13687
14442
|
'top',
|
|
14443
|
+
'rotate',
|
|
14444
|
+
'scale',
|
|
13688
14445
|
'width',
|
|
13689
14446
|
'zIndex'
|
|
13690
14447
|
]);
|
|
@@ -17334,6 +18091,15 @@ class WidgetInspectorComponent {
|
|
|
17334
18091
|
</div>
|
|
17335
18092
|
</ui-accordion>
|
|
17336
18093
|
|
|
18094
|
+
<ui-accordion title="Transform" [expanded]="false">
|
|
18095
|
+
<div [class.pointer-events-none]="readOnly()" [class.opacity-60]="readOnly()">
|
|
18096
|
+
<inspector-transform-section
|
|
18097
|
+
[style]="currentStyle()"
|
|
18098
|
+
(styleChange)="onStyleChange($event)">
|
|
18099
|
+
</inspector-transform-section>
|
|
18100
|
+
</div>
|
|
18101
|
+
</ui-accordion>
|
|
18102
|
+
|
|
17337
18103
|
<ui-accordion title="Position" [expanded]="false">
|
|
17338
18104
|
<div [class.pointer-events-none]="readOnly()" [class.opacity-60]="readOnly()">
|
|
17339
18105
|
<inspector-position-section
|
|
@@ -17366,7 +18132,7 @@ class WidgetInspectorComponent {
|
|
|
17366
18132
|
[config]="inspectorField()"
|
|
17367
18133
|
[allFields]="stateService.getSelectedScopeFields()"
|
|
17368
18134
|
[readOnly]="readOnly()"
|
|
17369
|
-
[excludeSections]="['Layout', 'Spacing', 'Size', 'Typography', 'Appearance', 'Box Model', 'Position', 'Effects', 'Advanced']"
|
|
18135
|
+
[excludeSections]="['Layout', 'Spacing', 'Size', 'Typography', 'Appearance', 'Box Model', 'Position', 'Effects', 'Transform', 'Advanced']"
|
|
17370
18136
|
(configChange)="onFieldConfigChange($event)">
|
|
17371
18137
|
</app-dynamic-properties>
|
|
17372
18138
|
</div>
|
|
@@ -17406,7 +18172,7 @@ class WidgetInspectorComponent {
|
|
|
17406
18172
|
</div>
|
|
17407
18173
|
`, isInline: true, styles: [":host{display:block;height:100%}.custom-scrollbar::-webkit-scrollbar{width:8px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#94a3b8}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: UiAccordionComponent, selector: "ui-accordion", inputs: ["title", "subtitle", "expanded", "showAdd"] }, { kind: "component", type:
|
|
17408
18174
|
// Style Sections
|
|
17409
|
-
InspectorSpacingSectionComponent, selector: "inspector-spacing-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorSizeSectionComponent, selector: "inspector-size-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorTypographySectionComponent, selector: "inspector-typography-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBordersSectionComponent, selector: "inspector-borders-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorLayoutSectionComponent, selector: "inspector-layout-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBackgroundsSectionComponent, selector: "inspector-backgrounds-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorEffectsSectionComponent, selector: "inspector-effects-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorPositionSectionComponent, selector: "inspector-position-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorAdvancedSectionComponent, selector: "inspector-advanced-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type:
|
|
18175
|
+
InspectorSpacingSectionComponent, selector: "inspector-spacing-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorSizeSectionComponent, selector: "inspector-size-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorTypographySectionComponent, selector: "inspector-typography-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBordersSectionComponent, selector: "inspector-borders-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorLayoutSectionComponent, selector: "inspector-layout-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBackgroundsSectionComponent, selector: "inspector-backgrounds-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorEffectsSectionComponent, selector: "inspector-effects-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorPositionSectionComponent, selector: "inspector-position-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorTransformSectionComponent, selector: "inspector-transform-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorAdvancedSectionComponent, selector: "inspector-advanced-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type:
|
|
17410
18176
|
// Functional Panels (All restored)
|
|
17411
18177
|
DynamicPropertiesComponent, selector: "app-dynamic-properties", inputs: ["onPropertyChange", "config", "readOnly", "includeSections", "excludeSections", "allFields"], outputs: ["configChange"] }, { kind: "component", type: DataPanelComponent, selector: "app-data-panel", inputs: ["config", "readOnly", "dataConsumer", "bindingShape", "dataTargetPath", "widgetType", "allFields"], outputs: ["configChange"] }, { kind: "component", type: RulesPanelComponent, selector: "app-rules-panel", inputs: ["readOnly", "rules", "allFields"], outputs: ["rulesChange"] }] });
|
|
17412
18178
|
}
|
|
@@ -17425,6 +18191,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
17425
18191
|
InspectorBackgroundsSectionComponent,
|
|
17426
18192
|
InspectorEffectsSectionComponent,
|
|
17427
18193
|
InspectorPositionSectionComponent,
|
|
18194
|
+
InspectorTransformSectionComponent,
|
|
17428
18195
|
InspectorAdvancedSectionComponent,
|
|
17429
18196
|
// Functional Panels (All restored)
|
|
17430
18197
|
DynamicPropertiesComponent,
|
|
@@ -17541,6 +18308,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
17541
18308
|
</div>
|
|
17542
18309
|
</ui-accordion>
|
|
17543
18310
|
|
|
18311
|
+
<ui-accordion title="Transform" [expanded]="false">
|
|
18312
|
+
<div [class.pointer-events-none]="readOnly()" [class.opacity-60]="readOnly()">
|
|
18313
|
+
<inspector-transform-section
|
|
18314
|
+
[style]="currentStyle()"
|
|
18315
|
+
(styleChange)="onStyleChange($event)">
|
|
18316
|
+
</inspector-transform-section>
|
|
18317
|
+
</div>
|
|
18318
|
+
</ui-accordion>
|
|
18319
|
+
|
|
17544
18320
|
<ui-accordion title="Position" [expanded]="false">
|
|
17545
18321
|
<div [class.pointer-events-none]="readOnly()" [class.opacity-60]="readOnly()">
|
|
17546
18322
|
<inspector-position-section
|
|
@@ -17573,7 +18349,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
17573
18349
|
[config]="inspectorField()"
|
|
17574
18350
|
[allFields]="stateService.getSelectedScopeFields()"
|
|
17575
18351
|
[readOnly]="readOnly()"
|
|
17576
|
-
[excludeSections]="['Layout', 'Spacing', 'Size', 'Typography', 'Appearance', 'Box Model', 'Position', 'Effects', 'Advanced']"
|
|
18352
|
+
[excludeSections]="['Layout', 'Spacing', 'Size', 'Typography', 'Appearance', 'Box Model', 'Position', 'Effects', 'Transform', 'Advanced']"
|
|
17577
18353
|
(configChange)="onFieldConfigChange($event)">
|
|
17578
18354
|
</app-dynamic-properties>
|
|
17579
18355
|
</div>
|
|
@@ -17683,39 +18459,6 @@ class FormSettingsInspectorComponent {
|
|
|
17683
18459
|
</div>
|
|
17684
18460
|
|
|
17685
18461
|
<div class="h-px bg-border-default my-1"></div>
|
|
17686
|
-
|
|
17687
|
-
<div class="flex flex-col gap-1">
|
|
17688
|
-
<label class="text-[10px] text-text-primary opacity-70 uppercase font-semibold">Submit Button</label>
|
|
17689
|
-
<input
|
|
17690
|
-
[ngModel]="schema().submitButtonText"
|
|
17691
|
-
[disabled]="readOnly()"
|
|
17692
|
-
(ngModelChange)="updateSettings('submitButtonText', $event)"
|
|
17693
|
-
placeholder="Submit"
|
|
17694
|
-
class="h-8 w-full rounded border border-border-default px-2 text-[12px] focus:border-focus-border focus:ring-1 focus:ring-focus-border outline-none bg-surface-default">
|
|
17695
|
-
</div>
|
|
17696
|
-
|
|
17697
|
-
<div class="flex flex-col gap-1">
|
|
17698
|
-
<label class="text-[10px] text-text-primary opacity-70 uppercase font-semibold">Reset Button</label>
|
|
17699
|
-
<div class="flex items-center gap-2 mb-1">
|
|
17700
|
-
<input
|
|
17701
|
-
type="checkbox"
|
|
17702
|
-
[ngModel]="schema().showResetButton !== false"
|
|
17703
|
-
[disabled]="readOnly()"
|
|
17704
|
-
(ngModelChange)="updateSettings('showResetButton', $event)"
|
|
17705
|
-
id="showReset"
|
|
17706
|
-
class="h-3.5 w-3.5 rounded border-border-default text-primary-500 focus:ring-primary-500">
|
|
17707
|
-
<label for="showReset" class="text-[12px] text-text-primary">Show Reset Button</label>
|
|
17708
|
-
</div>
|
|
17709
|
-
|
|
17710
|
-
@if (schema().showResetButton !== false) {
|
|
17711
|
-
<input
|
|
17712
|
-
[ngModel]="schema().resetButtonText"
|
|
17713
|
-
[disabled]="readOnly()"
|
|
17714
|
-
(ngModelChange)="updateSettings('resetButtonText', $event)"
|
|
17715
|
-
placeholder="Reset"
|
|
17716
|
-
class="h-8 w-full rounded border border-border-default px-2 text-[12px] focus:border-focus-border focus:ring-1 focus:ring-focus-border outline-none bg-surface-default">
|
|
17717
|
-
}
|
|
17718
|
-
</div>
|
|
17719
18462
|
</div>
|
|
17720
18463
|
}
|
|
17721
18464
|
|
|
@@ -17769,7 +18512,7 @@ class FormSettingsInspectorComponent {
|
|
|
17769
18512
|
|
|
17770
18513
|
</div>
|
|
17771
18514
|
</div>
|
|
17772
|
-
`, isInline: true, styles: [":host{display:block;height:100%}.custom-scrollbar::-webkit-scrollbar{width:8px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#94a3b8}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.
|
|
18515
|
+
`, isInline: true, styles: [":host{display:block;height:100%}.custom-scrollbar::-webkit-scrollbar{width:8px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#94a3b8}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: UiAccordionComponent, selector: "ui-accordion", inputs: ["title", "subtitle", "expanded", "showAdd"] }, { kind: "component", type: InspectorLayoutSectionComponent, selector: "inspector-layout-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBackgroundsSectionComponent, selector: "inspector-backgrounds-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBordersSectionComponent, selector: "inspector-borders-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorEffectsSectionComponent, selector: "inspector-effects-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorAdvancedSectionComponent, selector: "inspector-advanced-section", inputs: ["style"], outputs: ["styleChange"] }] });
|
|
17773
18516
|
}
|
|
17774
18517
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormSettingsInspectorComponent, decorators: [{
|
|
17775
18518
|
type: Component,
|
|
@@ -17835,39 +18578,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
17835
18578
|
</div>
|
|
17836
18579
|
|
|
17837
18580
|
<div class="h-px bg-border-default my-1"></div>
|
|
17838
|
-
|
|
17839
|
-
<div class="flex flex-col gap-1">
|
|
17840
|
-
<label class="text-[10px] text-text-primary opacity-70 uppercase font-semibold">Submit Button</label>
|
|
17841
|
-
<input
|
|
17842
|
-
[ngModel]="schema().submitButtonText"
|
|
17843
|
-
[disabled]="readOnly()"
|
|
17844
|
-
(ngModelChange)="updateSettings('submitButtonText', $event)"
|
|
17845
|
-
placeholder="Submit"
|
|
17846
|
-
class="h-8 w-full rounded border border-border-default px-2 text-[12px] focus:border-focus-border focus:ring-1 focus:ring-focus-border outline-none bg-surface-default">
|
|
17847
|
-
</div>
|
|
17848
|
-
|
|
17849
|
-
<div class="flex flex-col gap-1">
|
|
17850
|
-
<label class="text-[10px] text-text-primary opacity-70 uppercase font-semibold">Reset Button</label>
|
|
17851
|
-
<div class="flex items-center gap-2 mb-1">
|
|
17852
|
-
<input
|
|
17853
|
-
type="checkbox"
|
|
17854
|
-
[ngModel]="schema().showResetButton !== false"
|
|
17855
|
-
[disabled]="readOnly()"
|
|
17856
|
-
(ngModelChange)="updateSettings('showResetButton', $event)"
|
|
17857
|
-
id="showReset"
|
|
17858
|
-
class="h-3.5 w-3.5 rounded border-border-default text-primary-500 focus:ring-primary-500">
|
|
17859
|
-
<label for="showReset" class="text-[12px] text-text-primary">Show Reset Button</label>
|
|
17860
|
-
</div>
|
|
17861
|
-
|
|
17862
|
-
@if (schema().showResetButton !== false) {
|
|
17863
|
-
<input
|
|
17864
|
-
[ngModel]="schema().resetButtonText"
|
|
17865
|
-
[disabled]="readOnly()"
|
|
17866
|
-
(ngModelChange)="updateSettings('resetButtonText', $event)"
|
|
17867
|
-
placeholder="Reset"
|
|
17868
|
-
class="h-8 w-full rounded border border-border-default px-2 text-[12px] focus:border-focus-border focus:ring-1 focus:ring-focus-border outline-none bg-surface-default">
|
|
17869
|
-
}
|
|
17870
|
-
</div>
|
|
17871
18581
|
</div>
|
|
17872
18582
|
}
|
|
17873
18583
|
|
|
@@ -17924,165 +18634,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
17924
18634
|
`, styles: [":host{display:block;height:100%}.custom-scrollbar::-webkit-scrollbar{width:8px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:4px}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#94a3b8}\n"] }]
|
|
17925
18635
|
}] });
|
|
17926
18636
|
|
|
17927
|
-
class UiTabComponent {
|
|
17928
|
-
label = '';
|
|
17929
|
-
name = ''; // Unique key for controlled mode
|
|
17930
|
-
disabled = false;
|
|
17931
|
-
badge;
|
|
17932
|
-
badgeTone = 'neutral';
|
|
17933
|
-
template;
|
|
17934
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17935
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: UiTabComponent, isStandalone: true, selector: "ui-tab", inputs: { label: "label", name: "name", disabled: "disabled", badge: "badge", badgeTone: "badgeTone" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["tpl"], descendants: true, static: true }], ngImport: i0, template: `<ng-template #tpl><ng-content></ng-content></ng-template>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
17936
|
-
}
|
|
17937
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabComponent, decorators: [{
|
|
17938
|
-
type: Component,
|
|
17939
|
-
args: [{
|
|
17940
|
-
selector: 'ui-tab',
|
|
17941
|
-
standalone: true,
|
|
17942
|
-
imports: [CommonModule],
|
|
17943
|
-
template: `<ng-template #tpl><ng-content></ng-content></ng-template>`
|
|
17944
|
-
}]
|
|
17945
|
-
}], propDecorators: { label: [{
|
|
17946
|
-
type: Input
|
|
17947
|
-
}], name: [{
|
|
17948
|
-
type: Input
|
|
17949
|
-
}], disabled: [{
|
|
17950
|
-
type: Input
|
|
17951
|
-
}], badge: [{
|
|
17952
|
-
type: Input
|
|
17953
|
-
}], badgeTone: [{
|
|
17954
|
-
type: Input
|
|
17955
|
-
}], template: [{
|
|
17956
|
-
type: ViewChild,
|
|
17957
|
-
args: ['tpl', { static: true }]
|
|
17958
|
-
}] } });
|
|
17959
|
-
class UiTabsComponent {
|
|
17960
|
-
tabQuery;
|
|
17961
|
-
activeTab;
|
|
17962
|
-
activeTabChange = new EventEmitter();
|
|
17963
|
-
// Internal state if uncontrolled
|
|
17964
|
-
_internalIndex = 0;
|
|
17965
|
-
tabs = [];
|
|
17966
|
-
ngAfterContentInit() {
|
|
17967
|
-
this.tabs = this.tabQuery.toArray();
|
|
17968
|
-
}
|
|
17969
|
-
isActive(tab) {
|
|
17970
|
-
if (this.activeTab !== undefined) {
|
|
17971
|
-
return this.activeTab === (tab.name || tab.label);
|
|
17972
|
-
}
|
|
17973
|
-
return this.tabs.indexOf(tab) === this._internalIndex;
|
|
17974
|
-
}
|
|
17975
|
-
activate(tab) {
|
|
17976
|
-
if (tab.disabled)
|
|
17977
|
-
return;
|
|
17978
|
-
const key = tab.name || tab.label;
|
|
17979
|
-
if (this.activeTab !== undefined) {
|
|
17980
|
-
this.activeTabChange.emit(key);
|
|
17981
|
-
}
|
|
17982
|
-
else {
|
|
17983
|
-
this._internalIndex = this.tabs.indexOf(tab);
|
|
17984
|
-
}
|
|
17985
|
-
}
|
|
17986
|
-
get activeTemplate() {
|
|
17987
|
-
if (this.tabs.length === 0)
|
|
17988
|
-
return null;
|
|
17989
|
-
let activeTab;
|
|
17990
|
-
if (this.activeTab !== undefined) {
|
|
17991
|
-
activeTab = this.tabs.find(t => (t.name || t.label) === this.activeTab);
|
|
17992
|
-
}
|
|
17993
|
-
else {
|
|
17994
|
-
activeTab = this.tabs[this._internalIndex];
|
|
17995
|
-
}
|
|
17996
|
-
return activeTab?.template || null;
|
|
17997
|
-
}
|
|
17998
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
17999
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: UiTabsComponent, isStandalone: true, selector: "ui-tabs", inputs: { activeTab: "activeTab" }, outputs: { activeTabChange: "activeTabChange" }, queries: [{ propertyName: "tabQuery", predicate: UiTabComponent }], ngImport: i0, template: `
|
|
18000
|
-
<div class="flex flex-col min-h-0 h-full">
|
|
18001
|
-
<div class="flex items-center gap-1 px-3 border-b border-slate-200 bg-white shrink-0">
|
|
18002
|
-
<button
|
|
18003
|
-
*ngFor="let tab of tabs; let i = index"
|
|
18004
|
-
(click)="activate(tab)"
|
|
18005
|
-
class="relative h-10 px-3 text-xs font-semibold transition-colors rounded-t-md border-b-2"
|
|
18006
|
-
[class.text-accent-600]="isActive(tab)"
|
|
18007
|
-
[class.border-accent-600]="isActive(tab)"
|
|
18008
|
-
[class.text-ink-500]="!isActive(tab)"
|
|
18009
|
-
[class.border-transparent]="!isActive(tab)"
|
|
18010
|
-
[class.hover:text-ink-700]="!isActive(tab)"
|
|
18011
|
-
[disabled]="tab.disabled"
|
|
18012
|
-
>
|
|
18013
|
-
<span class="flex items-center gap-2">
|
|
18014
|
-
{{ tab.label }}
|
|
18015
|
-
<span *ngIf="tab.badge" class="text-[10px] px-1.5 py-0.5 rounded-full border"
|
|
18016
|
-
[class.bg-accent-50]="tab.badgeTone === 'accent'"
|
|
18017
|
-
[class.border-accent-200]="tab.badgeTone === 'accent'"
|
|
18018
|
-
[class.text-accent-700]="tab.badgeTone === 'accent'"
|
|
18019
|
-
[class.bg-slate-100]="tab.badgeTone === 'neutral'"
|
|
18020
|
-
[class.border-slate-200]="tab.badgeTone === 'neutral'"
|
|
18021
|
-
[class.text-slate-600]="tab.badgeTone === 'neutral'">
|
|
18022
|
-
{{ tab.badge }}
|
|
18023
|
-
</span>
|
|
18024
|
-
</span>
|
|
18025
|
-
</button>
|
|
18026
|
-
</div>
|
|
18027
|
-
|
|
18028
|
-
<div class="flex-1 min-h-0 overflow-hidden bg-slate-50/30">
|
|
18029
|
-
<ng-container *ngIf="activeTemplate">
|
|
18030
|
-
<ng-container *ngTemplateOutlet="activeTemplate"></ng-container>
|
|
18031
|
-
</ng-container>
|
|
18032
|
-
</div>
|
|
18033
|
-
</div>
|
|
18034
|
-
`, isInline: true, styles: [":host{display:block;height:100%}\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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
18035
|
-
}
|
|
18036
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabsComponent, decorators: [{
|
|
18037
|
-
type: Component,
|
|
18038
|
-
args: [{ selector: 'ui-tabs', standalone: true, imports: [CommonModule], template: `
|
|
18039
|
-
<div class="flex flex-col min-h-0 h-full">
|
|
18040
|
-
<div class="flex items-center gap-1 px-3 border-b border-slate-200 bg-white shrink-0">
|
|
18041
|
-
<button
|
|
18042
|
-
*ngFor="let tab of tabs; let i = index"
|
|
18043
|
-
(click)="activate(tab)"
|
|
18044
|
-
class="relative h-10 px-3 text-xs font-semibold transition-colors rounded-t-md border-b-2"
|
|
18045
|
-
[class.text-accent-600]="isActive(tab)"
|
|
18046
|
-
[class.border-accent-600]="isActive(tab)"
|
|
18047
|
-
[class.text-ink-500]="!isActive(tab)"
|
|
18048
|
-
[class.border-transparent]="!isActive(tab)"
|
|
18049
|
-
[class.hover:text-ink-700]="!isActive(tab)"
|
|
18050
|
-
[disabled]="tab.disabled"
|
|
18051
|
-
>
|
|
18052
|
-
<span class="flex items-center gap-2">
|
|
18053
|
-
{{ tab.label }}
|
|
18054
|
-
<span *ngIf="tab.badge" class="text-[10px] px-1.5 py-0.5 rounded-full border"
|
|
18055
|
-
[class.bg-accent-50]="tab.badgeTone === 'accent'"
|
|
18056
|
-
[class.border-accent-200]="tab.badgeTone === 'accent'"
|
|
18057
|
-
[class.text-accent-700]="tab.badgeTone === 'accent'"
|
|
18058
|
-
[class.bg-slate-100]="tab.badgeTone === 'neutral'"
|
|
18059
|
-
[class.border-slate-200]="tab.badgeTone === 'neutral'"
|
|
18060
|
-
[class.text-slate-600]="tab.badgeTone === 'neutral'">
|
|
18061
|
-
{{ tab.badge }}
|
|
18062
|
-
</span>
|
|
18063
|
-
</span>
|
|
18064
|
-
</button>
|
|
18065
|
-
</div>
|
|
18066
|
-
|
|
18067
|
-
<div class="flex-1 min-h-0 overflow-hidden bg-slate-50/30">
|
|
18068
|
-
<ng-container *ngIf="activeTemplate">
|
|
18069
|
-
<ng-container *ngTemplateOutlet="activeTemplate"></ng-container>
|
|
18070
|
-
</ng-container>
|
|
18071
|
-
</div>
|
|
18072
|
-
</div>
|
|
18073
|
-
`, styles: [":host{display:block;height:100%}\n"] }]
|
|
18074
|
-
}], propDecorators: { tabQuery: [{
|
|
18075
|
-
type: ContentChildren,
|
|
18076
|
-
args: [UiTabComponent]
|
|
18077
|
-
}], activeTab: [{
|
|
18078
|
-
type: Input
|
|
18079
|
-
}], activeTabChange: [{
|
|
18080
|
-
type: Output
|
|
18081
|
-
}] } });
|
|
18082
|
-
|
|
18083
18637
|
class PropertiesPanelComponent {
|
|
18084
18638
|
state;
|
|
18085
18639
|
injector;
|
|
18640
|
+
layoutInspectorTabs = ['Style', 'Settings'];
|
|
18641
|
+
activeLayoutInspectorTab = signal('Style');
|
|
18086
18642
|
spacingOptions = [
|
|
18087
18643
|
{ label: 'None', value: 'none' },
|
|
18088
18644
|
{ label: 'XS', value: 'xs' },
|
|
@@ -18105,9 +18661,11 @@ class PropertiesPanelComponent {
|
|
|
18105
18661
|
// No need to initialize form settings manually anymore, component inputs handle it
|
|
18106
18662
|
// Track the previous widget to avoid unnecessary re-renders
|
|
18107
18663
|
let previousWidgetId = null;
|
|
18664
|
+
let previousLayoutNodeKey = null;
|
|
18108
18665
|
effect(() => {
|
|
18109
18666
|
const node = this.state.selectedNode();
|
|
18110
18667
|
const currentWidgetId = (node && node.type === 'widget') ? node.id : null;
|
|
18668
|
+
const currentLayoutNodeKey = (node && node.type !== 'widget') ? `${node.type}:${node.id}` : null;
|
|
18111
18669
|
// Only re-render if the widget actually changed
|
|
18112
18670
|
if (currentWidgetId !== previousWidgetId) {
|
|
18113
18671
|
previousWidgetId = currentWidgetId;
|
|
@@ -18120,6 +18678,12 @@ class PropertiesPanelComponent {
|
|
|
18120
18678
|
this.inspectorContainer.clear();
|
|
18121
18679
|
}
|
|
18122
18680
|
}
|
|
18681
|
+
if (currentLayoutNodeKey !== previousLayoutNodeKey) {
|
|
18682
|
+
previousLayoutNodeKey = currentLayoutNodeKey;
|
|
18683
|
+
if (currentLayoutNodeKey) {
|
|
18684
|
+
this.activeLayoutInspectorTab.set('Style');
|
|
18685
|
+
}
|
|
18686
|
+
}
|
|
18123
18687
|
});
|
|
18124
18688
|
}
|
|
18125
18689
|
responsiveWidthOptions(includeInherit) {
|
|
@@ -18359,7 +18923,7 @@ class PropertiesPanelComponent {
|
|
|
18359
18923
|
this.state.selectNode(null);
|
|
18360
18924
|
}
|
|
18361
18925
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: PropertiesPanelComponent, deps: [{ token: DesignerStateService }, { token: WIDGET_DEFINITIONS }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
|
|
18362
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
18926
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: PropertiesPanelComponent, isStandalone: true, selector: "app-properties-panel", viewQueries: [{ propertyName: "inspectorContainer", first: true, predicate: ["inspectorContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: `
|
|
18363
18927
|
<div class="properties-shell h-full border-l border-border-default bg-surface-default flex flex-col font-sans text-[12px]">
|
|
18364
18928
|
|
|
18365
18929
|
<div *ngIf="state.selectedNode() as node; else noSelection" class="flex flex-col h-full">
|
|
@@ -18386,239 +18950,182 @@ class PropertiesPanelComponent {
|
|
|
18386
18950
|
</div>
|
|
18387
18951
|
</div>
|
|
18388
18952
|
|
|
18389
|
-
|
|
18390
|
-
|
|
18391
|
-
|
|
18392
|
-
|
|
18393
|
-
|
|
18394
|
-
|
|
18395
|
-
|
|
18396
|
-
|
|
18397
|
-
|
|
18398
|
-
|
|
18399
|
-
|
|
18400
|
-
|
|
18401
|
-
<!-- Presets -->
|
|
18402
|
-
<div class="grid grid-cols-3 gap-2 mb-3">
|
|
18403
|
-
<button (click)="applyPreset(node.id, 1)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="1 Column">
|
|
18404
|
-
<div class="flex gap-1 w-full h-4 justify-center px-1">
|
|
18405
|
-
<div class="w-full bg-border-default rounded-sm"></div>
|
|
18406
|
-
</div>
|
|
18407
|
-
</button>
|
|
18408
|
-
<button (click)="applyPreset(node.id, 2)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="2 Columns">
|
|
18409
|
-
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
18410
|
-
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
18411
|
-
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
18412
|
-
</div>
|
|
18413
|
-
</button>
|
|
18414
|
-
<button (click)="applyPreset(node.id, 3)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="3 Columns">
|
|
18415
|
-
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
18416
|
-
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
18417
|
-
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
18418
|
-
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
18419
|
-
</div>
|
|
18420
|
-
</button>
|
|
18421
|
-
<button (click)="applyPreset(node.id, 4)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="4 Columns">
|
|
18422
|
-
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
18423
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18424
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18425
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18426
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18427
|
-
</div>
|
|
18428
|
-
</button>
|
|
18429
|
-
<button (click)="applyPreset(node.id, 6)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="6 Columns">
|
|
18430
|
-
<span class="text-[12px] text-text-primary font-medium">6 Col</span>
|
|
18431
|
-
</button>
|
|
18432
|
-
<button (click)="applyPreset(node.id, 12)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="12 Columns">
|
|
18433
|
-
<span class="text-[12px] text-text-primary font-medium">12 Col</span>
|
|
18434
|
-
</button>
|
|
18435
|
-
</div>
|
|
18436
|
-
|
|
18437
|
-
<!-- Manual Actions -->
|
|
18438
|
-
<div class="flex flex-col gap-2">
|
|
18439
|
-
<button (click)="addColumn(node.id)" class="w-full h-9 bg-primary-500 text-white rounded-md hover:opacity-90 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
18440
|
-
<lucide-icon name="plus" class="w-4 h-4"></lucide-icon> Add Column
|
|
18441
|
-
</button>
|
|
18442
|
-
</div>
|
|
18443
|
-
</div>
|
|
18444
|
-
|
|
18445
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18446
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Layout</div>
|
|
18447
|
-
<inspector-layout-section
|
|
18448
|
-
[style]="nodeStyle(node)"
|
|
18449
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18450
|
-
</inspector-layout-section>
|
|
18451
|
-
</div>
|
|
18452
|
-
|
|
18453
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18454
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Spacing</div>
|
|
18455
|
-
<inspector-spacing-section
|
|
18456
|
-
[style]="nodeStyle(node)"
|
|
18457
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18458
|
-
</inspector-spacing-section>
|
|
18459
|
-
</div>
|
|
18460
|
-
|
|
18461
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18462
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Size</div>
|
|
18463
|
-
<inspector-size-section
|
|
18464
|
-
[style]="nodeStyle(node)"
|
|
18465
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18466
|
-
</inspector-size-section>
|
|
18467
|
-
</div>
|
|
18468
|
-
|
|
18469
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18470
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Backgrounds</div>
|
|
18471
|
-
<inspector-backgrounds-section
|
|
18472
|
-
[style]="nodeStyle(node)"
|
|
18473
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18474
|
-
</inspector-backgrounds-section>
|
|
18475
|
-
</div>
|
|
18476
|
-
|
|
18477
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18478
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Borders</div>
|
|
18479
|
-
<inspector-borders-section
|
|
18480
|
-
[style]="nodeStyle(node)"
|
|
18481
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18482
|
-
</inspector-borders-section>
|
|
18483
|
-
</div>
|
|
18484
|
-
|
|
18485
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18486
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Effects</div>
|
|
18487
|
-
<inspector-effects-section
|
|
18488
|
-
[style]="nodeStyle(node)"
|
|
18489
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18490
|
-
</inspector-effects-section>
|
|
18491
|
-
</div>
|
|
18492
|
-
|
|
18493
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18494
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Advanced</div>
|
|
18495
|
-
<inspector-advanced-section
|
|
18496
|
-
[style]="nodeStyle(node)"
|
|
18497
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18498
|
-
</inspector-advanced-section>
|
|
18499
|
-
</div>
|
|
18500
|
-
</div>
|
|
18501
|
-
</ng-container>
|
|
18502
|
-
<ng-container *ngIf="node.type === 'col'">
|
|
18503
|
-
<div class="inspector-stack space-y-4">
|
|
18504
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18505
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Responsive Width (1-12)</div>
|
|
18506
|
-
|
|
18507
|
-
<!-- XS (Mobile) -->
|
|
18508
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18509
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XS</span>
|
|
18510
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xs" (ngModelChange)="onResponsiveChange(node.id, 'xs', $event)">
|
|
18511
|
-
<option *ngFor="let option of responsiveWidthOptions(false)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18512
|
-
</select>
|
|
18513
|
-
</div>
|
|
18514
|
-
|
|
18515
|
-
<!-- SM (Large Phones) -->
|
|
18516
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18517
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">SM</span>
|
|
18518
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.sm" (ngModelChange)="onResponsiveChange(node.id, 'sm', $event)">
|
|
18519
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18520
|
-
</select>
|
|
18521
|
-
</div>
|
|
18522
|
-
|
|
18523
|
-
<!-- MD (Tablet) -->
|
|
18524
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18525
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">MD</span>
|
|
18526
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.md" (ngModelChange)="onResponsiveChange(node.id, 'md', $event)">
|
|
18527
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18528
|
-
</select>
|
|
18529
|
-
</div>
|
|
18530
|
-
|
|
18531
|
-
<!-- LG (Desktop) -->
|
|
18532
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18533
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">LG</span>
|
|
18534
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.lg" (ngModelChange)="onResponsiveChange(node.id, 'lg', $event)">
|
|
18535
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18536
|
-
</select>
|
|
18537
|
-
</div>
|
|
18538
|
-
|
|
18539
|
-
<!-- XL (Large Desktop) -->
|
|
18540
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18541
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XL</span>
|
|
18542
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xl" (ngModelChange)="onResponsiveChange(node.id, 'xl', $event)">
|
|
18543
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18544
|
-
</select>
|
|
18545
|
-
</div>
|
|
18546
|
-
|
|
18547
|
-
<!-- 2XL (Extra Large) -->
|
|
18548
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18549
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">2XL</span>
|
|
18550
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive ? node.responsive['2xl'] : undefined" (ngModelChange)="onResponsiveChange(node.id, '2xl', $event)">
|
|
18551
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18552
|
-
</select>
|
|
18553
|
-
</div>
|
|
18554
|
-
</div>
|
|
18555
|
-
|
|
18556
|
-
<div *ngIf="!state.isReadOnly()" class="inspector-card bg-red-50 border border-red-100 rounded-lg p-3">
|
|
18557
|
-
<button (click)="removeColumn(node.id)" class="w-full h-8 text-red-600 hover:text-red-700 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
18558
|
-
<lucide-icon name="trash-2" class="w-4 h-4"></lucide-icon> Remove Column
|
|
18559
|
-
</button>
|
|
18560
|
-
</div>
|
|
18953
|
+
<div class="flex items-center px-2 pt-2 border-b border-border-default bg-surface-default">
|
|
18954
|
+
@for (tab of layoutInspectorTabs; track tab) {
|
|
18955
|
+
<button
|
|
18956
|
+
type="button"
|
|
18957
|
+
(click)="activeLayoutInspectorTab.set(tab)"
|
|
18958
|
+
[class]="activeLayoutInspectorTab() === tab
|
|
18959
|
+
? 'px-2 pb-2 font-semibold text-primary-500 border-b-2 border-b-primary-500'
|
|
18960
|
+
: 'px-2 pb-2 text-text-primary opacity-60 hover:opacity-100 hover:text-text-primary border-b-2 border-transparent'">
|
|
18961
|
+
{{ tab }}
|
|
18962
|
+
</button>
|
|
18963
|
+
}
|
|
18964
|
+
</div>
|
|
18561
18965
|
|
|
18562
|
-
|
|
18563
|
-
|
|
18564
|
-
|
|
18565
|
-
|
|
18566
|
-
|
|
18567
|
-
|
|
18568
|
-
|
|
18966
|
+
<div class="flex-1 overflow-y-auto custom-scrollbar bg-surface-default">
|
|
18967
|
+
@if (activeLayoutInspectorTab() === 'Style') {
|
|
18968
|
+
<div class="flex flex-col" [class.pointer-events-none]="state.isReadOnly()" [class.opacity-60]="state.isReadOnly()">
|
|
18969
|
+
<ui-accordion title="Layout" [expanded]="true">
|
|
18970
|
+
<inspector-layout-section
|
|
18971
|
+
[style]="nodeStyle(node)"
|
|
18972
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18973
|
+
</inspector-layout-section>
|
|
18974
|
+
</ui-accordion>
|
|
18975
|
+
|
|
18976
|
+
<ui-accordion title="Spacing" [expanded]="false">
|
|
18977
|
+
<inspector-spacing-section
|
|
18978
|
+
[style]="nodeStyle(node)"
|
|
18979
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18980
|
+
</inspector-spacing-section>
|
|
18981
|
+
</ui-accordion>
|
|
18982
|
+
|
|
18983
|
+
<ui-accordion title="Size" [expanded]="false">
|
|
18984
|
+
<inspector-size-section
|
|
18985
|
+
[style]="nodeStyle(node)"
|
|
18986
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18987
|
+
</inspector-size-section>
|
|
18988
|
+
</ui-accordion>
|
|
18989
|
+
|
|
18990
|
+
<ui-accordion title="Backgrounds" [expanded]="false">
|
|
18991
|
+
<inspector-backgrounds-section
|
|
18992
|
+
[style]="nodeStyle(node)"
|
|
18993
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18994
|
+
</inspector-backgrounds-section>
|
|
18995
|
+
</ui-accordion>
|
|
18996
|
+
|
|
18997
|
+
<ui-accordion title="Borders" [expanded]="false">
|
|
18998
|
+
<inspector-borders-section
|
|
18999
|
+
[style]="nodeStyle(node)"
|
|
19000
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19001
|
+
</inspector-borders-section>
|
|
19002
|
+
</ui-accordion>
|
|
19003
|
+
|
|
19004
|
+
<ui-accordion title="Effects" [expanded]="false">
|
|
19005
|
+
<inspector-effects-section
|
|
19006
|
+
[style]="nodeStyle(node)"
|
|
19007
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19008
|
+
</inspector-effects-section>
|
|
19009
|
+
</ui-accordion>
|
|
19010
|
+
|
|
19011
|
+
<ui-accordion title="Advanced" [expanded]="false">
|
|
19012
|
+
<inspector-advanced-section
|
|
19013
|
+
[style]="nodeStyle(node)"
|
|
19014
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19015
|
+
</inspector-advanced-section>
|
|
19016
|
+
</ui-accordion>
|
|
19017
|
+
|
|
19018
|
+
<div class="h-10"></div>
|
|
19019
|
+
</div>
|
|
19020
|
+
}
|
|
19021
|
+
|
|
19022
|
+
@if (activeLayoutInspectorTab() === 'Settings') {
|
|
19023
|
+
<div class="p-4 flex flex-col gap-4">
|
|
19024
|
+
@if (node.type === 'row') {
|
|
19025
|
+
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm"
|
|
19026
|
+
[class.opacity-60]="state.isReadOnly()"
|
|
19027
|
+
[class.pointer-events-none]="state.isReadOnly()">
|
|
19028
|
+
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Column Structure</div>
|
|
19029
|
+
<div class="grid grid-cols-3 gap-2 mb-3">
|
|
19030
|
+
<button (click)="applyPreset(node.id, 1)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="1 Column">
|
|
19031
|
+
<div class="flex gap-1 w-full h-4 justify-center px-1">
|
|
19032
|
+
<div class="w-full bg-border-default rounded-sm"></div>
|
|
19033
|
+
</div>
|
|
19034
|
+
</button>
|
|
19035
|
+
<button (click)="applyPreset(node.id, 2)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="2 Columns">
|
|
19036
|
+
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
19037
|
+
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
19038
|
+
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
19039
|
+
</div>
|
|
19040
|
+
</button>
|
|
19041
|
+
<button (click)="applyPreset(node.id, 3)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="3 Columns">
|
|
19042
|
+
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
19043
|
+
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
19044
|
+
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
19045
|
+
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
19046
|
+
</div>
|
|
19047
|
+
</button>
|
|
19048
|
+
<button (click)="applyPreset(node.id, 4)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="4 Columns">
|
|
19049
|
+
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
19050
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19051
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19052
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19053
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19054
|
+
</div>
|
|
19055
|
+
</button>
|
|
19056
|
+
<button (click)="applyPreset(node.id, 6)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="6 Columns">
|
|
19057
|
+
<span class="text-[12px] text-text-primary font-medium">6 Col</span>
|
|
19058
|
+
</button>
|
|
19059
|
+
<button (click)="applyPreset(node.id, 12)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="12 Columns">
|
|
19060
|
+
<span class="text-[12px] text-text-primary font-medium">12 Col</span>
|
|
19061
|
+
</button>
|
|
19062
|
+
</div>
|
|
19063
|
+
<button (click)="addColumn(node.id)" class="w-full h-9 bg-primary-500 text-white rounded-md hover:opacity-90 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
19064
|
+
<lucide-icon name="plus" class="w-4 h-4"></lucide-icon> Add Column
|
|
19065
|
+
</button>
|
|
19066
|
+
</div>
|
|
19067
|
+
}
|
|
19068
|
+
|
|
19069
|
+
@if (node.type === 'col') {
|
|
19070
|
+
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm"
|
|
19071
|
+
[class.opacity-60]="state.isReadOnly()"
|
|
19072
|
+
[class.pointer-events-none]="state.isReadOnly()">
|
|
19073
|
+
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Responsive Width (1-12)</div>
|
|
19074
|
+
|
|
19075
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19076
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XS</span>
|
|
19077
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xs" (ngModelChange)="onResponsiveChange(node.id, 'xs', $event)">
|
|
19078
|
+
<option *ngFor="let option of responsiveWidthOptions(false)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19079
|
+
</select>
|
|
19080
|
+
</div>
|
|
18569
19081
|
|
|
18570
|
-
|
|
18571
|
-
|
|
18572
|
-
|
|
18573
|
-
|
|
18574
|
-
|
|
18575
|
-
|
|
18576
|
-
</div>
|
|
19082
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19083
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">SM</span>
|
|
19084
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.sm" (ngModelChange)="onResponsiveChange(node.id, 'sm', $event)">
|
|
19085
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19086
|
+
</select>
|
|
19087
|
+
</div>
|
|
18577
19088
|
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18582
|
-
|
|
18583
|
-
|
|
18584
|
-
</div>
|
|
19089
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19090
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">MD</span>
|
|
19091
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.md" (ngModelChange)="onResponsiveChange(node.id, 'md', $event)">
|
|
19092
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19093
|
+
</select>
|
|
19094
|
+
</div>
|
|
18585
19095
|
|
|
18586
|
-
|
|
18587
|
-
|
|
18588
|
-
|
|
18589
|
-
|
|
18590
|
-
|
|
18591
|
-
|
|
18592
|
-
</div>
|
|
19096
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19097
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">LG</span>
|
|
19098
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.lg" (ngModelChange)="onResponsiveChange(node.id, 'lg', $event)">
|
|
19099
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19100
|
+
</select>
|
|
19101
|
+
</div>
|
|
18593
19102
|
|
|
18594
|
-
|
|
18595
|
-
|
|
18596
|
-
|
|
18597
|
-
|
|
18598
|
-
|
|
18599
|
-
|
|
18600
|
-
</div>
|
|
19103
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19104
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XL</span>
|
|
19105
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xl" (ngModelChange)="onResponsiveChange(node.id, 'xl', $event)">
|
|
19106
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19107
|
+
</select>
|
|
19108
|
+
</div>
|
|
18601
19109
|
|
|
18602
|
-
|
|
18603
|
-
|
|
18604
|
-
|
|
18605
|
-
|
|
18606
|
-
|
|
18607
|
-
|
|
18608
|
-
|
|
19110
|
+
<div class="flex items-center gap-2">
|
|
19111
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">2XL</span>
|
|
19112
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive ? node.responsive['2xl'] : undefined" (ngModelChange)="onResponsiveChange(node.id, '2xl', $event)">
|
|
19113
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19114
|
+
</select>
|
|
19115
|
+
</div>
|
|
19116
|
+
</div>
|
|
18609
19117
|
|
|
18610
|
-
|
|
18611
|
-
|
|
18612
|
-
|
|
18613
|
-
|
|
18614
|
-
|
|
18615
|
-
|
|
18616
|
-
|
|
18617
|
-
|
|
18618
|
-
|
|
18619
|
-
|
|
18620
|
-
|
|
18621
|
-
</ui-tabs>
|
|
19118
|
+
@if (!state.isReadOnly()) {
|
|
19119
|
+
<div class="inspector-card bg-red-50 border border-red-100 rounded-lg p-3">
|
|
19120
|
+
<button (click)="removeColumn(node.id)" class="w-full h-8 text-red-600 hover:text-red-700 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
19121
|
+
<lucide-icon name="trash-2" class="w-4 h-4"></lucide-icon> Remove Column
|
|
19122
|
+
</button>
|
|
19123
|
+
</div>
|
|
19124
|
+
}
|
|
19125
|
+
}
|
|
19126
|
+
</div>
|
|
19127
|
+
}
|
|
19128
|
+
</div>
|
|
18622
19129
|
</ng-container>
|
|
18623
19130
|
</div>
|
|
18624
19131
|
|
|
@@ -18631,7 +19138,7 @@ class PropertiesPanelComponent {
|
|
|
18631
19138
|
</form-settings-inspector>
|
|
18632
19139
|
</ng-template>
|
|
18633
19140
|
</div>
|
|
18634
|
-
`, isInline: true, styles: [".custom-scrollbar::-webkit-scrollbar{width:6px}.custom-scrollbar::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:99px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}\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: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type:
|
|
19141
|
+
`, isInline: true, styles: [".custom-scrollbar::-webkit-scrollbar{width:6px}.custom-scrollbar::-webkit-scrollbar-thumb{background-color:#d1d5db;border-radius:99px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}\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: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i3$1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: UiAccordionComponent, selector: "ui-accordion", inputs: ["title", "subtitle", "expanded", "showAdd"] }, { kind: "component", type: WidgetInspectorComponent, selector: "widget-inspector", inputs: ["node", "field", "readOnly"], outputs: ["fieldChange", "styleChange", "rulesChange", "duplicate", "delete"] }, { kind: "component", type: FormSettingsInspectorComponent, selector: "form-settings-inspector", inputs: ["schema", "readOnly"], outputs: ["settingsChange", "styleChange"] }, { kind: "component", type: InspectorLayoutSectionComponent, selector: "inspector-layout-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorSpacingSectionComponent, selector: "inspector-spacing-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorSizeSectionComponent, selector: "inspector-size-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBackgroundsSectionComponent, selector: "inspector-backgrounds-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorBordersSectionComponent, selector: "inspector-borders-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorEffectsSectionComponent, selector: "inspector-effects-section", inputs: ["style"], outputs: ["styleChange"] }, { kind: "component", type: InspectorAdvancedSectionComponent, selector: "inspector-advanced-section", inputs: ["style"], outputs: ["styleChange"] }] });
|
|
18635
19142
|
}
|
|
18636
19143
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: PropertiesPanelComponent, decorators: [{
|
|
18637
19144
|
type: Component,
|
|
@@ -18639,8 +19146,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18639
19146
|
CommonModule,
|
|
18640
19147
|
FormsModule,
|
|
18641
19148
|
UiIconModule,
|
|
18642
|
-
|
|
18643
|
-
UiTabComponent,
|
|
19149
|
+
UiAccordionComponent,
|
|
18644
19150
|
WidgetInspectorComponent,
|
|
18645
19151
|
FormSettingsInspectorComponent,
|
|
18646
19152
|
InspectorLayoutSectionComponent,
|
|
@@ -18677,239 +19183,182 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
18677
19183
|
</div>
|
|
18678
19184
|
</div>
|
|
18679
19185
|
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18685
|
-
|
|
18686
|
-
|
|
18687
|
-
|
|
18688
|
-
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
<!-- Presets -->
|
|
18693
|
-
<div class="grid grid-cols-3 gap-2 mb-3">
|
|
18694
|
-
<button (click)="applyPreset(node.id, 1)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="1 Column">
|
|
18695
|
-
<div class="flex gap-1 w-full h-4 justify-center px-1">
|
|
18696
|
-
<div class="w-full bg-border-default rounded-sm"></div>
|
|
18697
|
-
</div>
|
|
18698
|
-
</button>
|
|
18699
|
-
<button (click)="applyPreset(node.id, 2)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="2 Columns">
|
|
18700
|
-
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
18701
|
-
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
18702
|
-
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
18703
|
-
</div>
|
|
18704
|
-
</button>
|
|
18705
|
-
<button (click)="applyPreset(node.id, 3)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="3 Columns">
|
|
18706
|
-
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
18707
|
-
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
18708
|
-
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
18709
|
-
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
18710
|
-
</div>
|
|
18711
|
-
</button>
|
|
18712
|
-
<button (click)="applyPreset(node.id, 4)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="4 Columns">
|
|
18713
|
-
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
18714
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18715
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18716
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18717
|
-
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
18718
|
-
</div>
|
|
18719
|
-
</button>
|
|
18720
|
-
<button (click)="applyPreset(node.id, 6)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="6 Columns">
|
|
18721
|
-
<span class="text-[12px] text-text-primary font-medium">6 Col</span>
|
|
18722
|
-
</button>
|
|
18723
|
-
<button (click)="applyPreset(node.id, 12)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="12 Columns">
|
|
18724
|
-
<span class="text-[12px] text-text-primary font-medium">12 Col</span>
|
|
18725
|
-
</button>
|
|
18726
|
-
</div>
|
|
18727
|
-
|
|
18728
|
-
<!-- Manual Actions -->
|
|
18729
|
-
<div class="flex flex-col gap-2">
|
|
18730
|
-
<button (click)="addColumn(node.id)" class="w-full h-9 bg-primary-500 text-white rounded-md hover:opacity-90 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
18731
|
-
<lucide-icon name="plus" class="w-4 h-4"></lucide-icon> Add Column
|
|
18732
|
-
</button>
|
|
18733
|
-
</div>
|
|
18734
|
-
</div>
|
|
18735
|
-
|
|
18736
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18737
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Layout</div>
|
|
18738
|
-
<inspector-layout-section
|
|
18739
|
-
[style]="nodeStyle(node)"
|
|
18740
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18741
|
-
</inspector-layout-section>
|
|
18742
|
-
</div>
|
|
18743
|
-
|
|
18744
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18745
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Spacing</div>
|
|
18746
|
-
<inspector-spacing-section
|
|
18747
|
-
[style]="nodeStyle(node)"
|
|
18748
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18749
|
-
</inspector-spacing-section>
|
|
18750
|
-
</div>
|
|
18751
|
-
|
|
18752
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18753
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Size</div>
|
|
18754
|
-
<inspector-size-section
|
|
18755
|
-
[style]="nodeStyle(node)"
|
|
18756
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18757
|
-
</inspector-size-section>
|
|
18758
|
-
</div>
|
|
18759
|
-
|
|
18760
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18761
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Backgrounds</div>
|
|
18762
|
-
<inspector-backgrounds-section
|
|
18763
|
-
[style]="nodeStyle(node)"
|
|
18764
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18765
|
-
</inspector-backgrounds-section>
|
|
18766
|
-
</div>
|
|
18767
|
-
|
|
18768
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18769
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Borders</div>
|
|
18770
|
-
<inspector-borders-section
|
|
18771
|
-
[style]="nodeStyle(node)"
|
|
18772
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18773
|
-
</inspector-borders-section>
|
|
18774
|
-
</div>
|
|
18775
|
-
|
|
18776
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18777
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Effects</div>
|
|
18778
|
-
<inspector-effects-section
|
|
18779
|
-
[style]="nodeStyle(node)"
|
|
18780
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18781
|
-
</inspector-effects-section>
|
|
18782
|
-
</div>
|
|
18783
|
-
|
|
18784
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18785
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Advanced</div>
|
|
18786
|
-
<inspector-advanced-section
|
|
18787
|
-
[style]="nodeStyle(node)"
|
|
18788
|
-
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
18789
|
-
</inspector-advanced-section>
|
|
18790
|
-
</div>
|
|
18791
|
-
</div>
|
|
18792
|
-
</ng-container>
|
|
18793
|
-
<ng-container *ngIf="node.type === 'col'">
|
|
18794
|
-
<div class="inspector-stack space-y-4">
|
|
18795
|
-
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm" [class.opacity-50]="state.isReadOnly()" [class.pointer-events-none]="state.isReadOnly()">
|
|
18796
|
-
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Responsive Width (1-12)</div>
|
|
18797
|
-
|
|
18798
|
-
<!-- XS (Mobile) -->
|
|
18799
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18800
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XS</span>
|
|
18801
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xs" (ngModelChange)="onResponsiveChange(node.id, 'xs', $event)">
|
|
18802
|
-
<option *ngFor="let option of responsiveWidthOptions(false)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18803
|
-
</select>
|
|
18804
|
-
</div>
|
|
18805
|
-
|
|
18806
|
-
<!-- SM (Large Phones) -->
|
|
18807
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18808
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">SM</span>
|
|
18809
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.sm" (ngModelChange)="onResponsiveChange(node.id, 'sm', $event)">
|
|
18810
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18811
|
-
</select>
|
|
18812
|
-
</div>
|
|
18813
|
-
|
|
18814
|
-
<!-- MD (Tablet) -->
|
|
18815
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18816
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">MD</span>
|
|
18817
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.md" (ngModelChange)="onResponsiveChange(node.id, 'md', $event)">
|
|
18818
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18819
|
-
</select>
|
|
18820
|
-
</div>
|
|
18821
|
-
|
|
18822
|
-
<!-- LG (Desktop) -->
|
|
18823
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18824
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">LG</span>
|
|
18825
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.lg" (ngModelChange)="onResponsiveChange(node.id, 'lg', $event)">
|
|
18826
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18827
|
-
</select>
|
|
18828
|
-
</div>
|
|
18829
|
-
|
|
18830
|
-
<!-- XL (Large Desktop) -->
|
|
18831
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18832
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XL</span>
|
|
18833
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xl" (ngModelChange)="onResponsiveChange(node.id, 'xl', $event)">
|
|
18834
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18835
|
-
</select>
|
|
18836
|
-
</div>
|
|
18837
|
-
|
|
18838
|
-
<!-- 2XL (Extra Large) -->
|
|
18839
|
-
<div class="flex items-center gap-2 mb-2">
|
|
18840
|
-
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">2XL</span>
|
|
18841
|
-
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive ? node.responsive['2xl'] : undefined" (ngModelChange)="onResponsiveChange(node.id, '2xl', $event)">
|
|
18842
|
-
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
18843
|
-
</select>
|
|
18844
|
-
</div>
|
|
18845
|
-
</div>
|
|
18846
|
-
|
|
18847
|
-
<div *ngIf="!state.isReadOnly()" class="inspector-card bg-red-50 border border-red-100 rounded-lg p-3">
|
|
18848
|
-
<button (click)="removeColumn(node.id)" class="w-full h-8 text-red-600 hover:text-red-700 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
18849
|
-
<lucide-icon name="trash-2" class="w-4 h-4"></lucide-icon> Remove Column
|
|
18850
|
-
</button>
|
|
18851
|
-
</div>
|
|
19186
|
+
<div class="flex items-center px-2 pt-2 border-b border-border-default bg-surface-default">
|
|
19187
|
+
@for (tab of layoutInspectorTabs; track tab) {
|
|
19188
|
+
<button
|
|
19189
|
+
type="button"
|
|
19190
|
+
(click)="activeLayoutInspectorTab.set(tab)"
|
|
19191
|
+
[class]="activeLayoutInspectorTab() === tab
|
|
19192
|
+
? 'px-2 pb-2 font-semibold text-primary-500 border-b-2 border-b-primary-500'
|
|
19193
|
+
: 'px-2 pb-2 text-text-primary opacity-60 hover:opacity-100 hover:text-text-primary border-b-2 border-transparent'">
|
|
19194
|
+
{{ tab }}
|
|
19195
|
+
</button>
|
|
19196
|
+
}
|
|
19197
|
+
</div>
|
|
18852
19198
|
|
|
18853
|
-
|
|
18854
|
-
|
|
18855
|
-
|
|
18856
|
-
|
|
18857
|
-
|
|
18858
|
-
|
|
18859
|
-
|
|
19199
|
+
<div class="flex-1 overflow-y-auto custom-scrollbar bg-surface-default">
|
|
19200
|
+
@if (activeLayoutInspectorTab() === 'Style') {
|
|
19201
|
+
<div class="flex flex-col" [class.pointer-events-none]="state.isReadOnly()" [class.opacity-60]="state.isReadOnly()">
|
|
19202
|
+
<ui-accordion title="Layout" [expanded]="true">
|
|
19203
|
+
<inspector-layout-section
|
|
19204
|
+
[style]="nodeStyle(node)"
|
|
19205
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19206
|
+
</inspector-layout-section>
|
|
19207
|
+
</ui-accordion>
|
|
19208
|
+
|
|
19209
|
+
<ui-accordion title="Spacing" [expanded]="false">
|
|
19210
|
+
<inspector-spacing-section
|
|
19211
|
+
[style]="nodeStyle(node)"
|
|
19212
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19213
|
+
</inspector-spacing-section>
|
|
19214
|
+
</ui-accordion>
|
|
19215
|
+
|
|
19216
|
+
<ui-accordion title="Size" [expanded]="false">
|
|
19217
|
+
<inspector-size-section
|
|
19218
|
+
[style]="nodeStyle(node)"
|
|
19219
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19220
|
+
</inspector-size-section>
|
|
19221
|
+
</ui-accordion>
|
|
19222
|
+
|
|
19223
|
+
<ui-accordion title="Backgrounds" [expanded]="false">
|
|
19224
|
+
<inspector-backgrounds-section
|
|
19225
|
+
[style]="nodeStyle(node)"
|
|
19226
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19227
|
+
</inspector-backgrounds-section>
|
|
19228
|
+
</ui-accordion>
|
|
19229
|
+
|
|
19230
|
+
<ui-accordion title="Borders" [expanded]="false">
|
|
19231
|
+
<inspector-borders-section
|
|
19232
|
+
[style]="nodeStyle(node)"
|
|
19233
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19234
|
+
</inspector-borders-section>
|
|
19235
|
+
</ui-accordion>
|
|
19236
|
+
|
|
19237
|
+
<ui-accordion title="Effects" [expanded]="false">
|
|
19238
|
+
<inspector-effects-section
|
|
19239
|
+
[style]="nodeStyle(node)"
|
|
19240
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19241
|
+
</inspector-effects-section>
|
|
19242
|
+
</ui-accordion>
|
|
19243
|
+
|
|
19244
|
+
<ui-accordion title="Advanced" [expanded]="false">
|
|
19245
|
+
<inspector-advanced-section
|
|
19246
|
+
[style]="nodeStyle(node)"
|
|
19247
|
+
(styleChange)="onNodeInspectorStyleChange(node.id, $event)">
|
|
19248
|
+
</inspector-advanced-section>
|
|
19249
|
+
</ui-accordion>
|
|
19250
|
+
|
|
19251
|
+
<div class="h-10"></div>
|
|
19252
|
+
</div>
|
|
19253
|
+
}
|
|
19254
|
+
|
|
19255
|
+
@if (activeLayoutInspectorTab() === 'Settings') {
|
|
19256
|
+
<div class="p-4 flex flex-col gap-4">
|
|
19257
|
+
@if (node.type === 'row') {
|
|
19258
|
+
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm"
|
|
19259
|
+
[class.opacity-60]="state.isReadOnly()"
|
|
19260
|
+
[class.pointer-events-none]="state.isReadOnly()">
|
|
19261
|
+
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Column Structure</div>
|
|
19262
|
+
<div class="grid grid-cols-3 gap-2 mb-3">
|
|
19263
|
+
<button (click)="applyPreset(node.id, 1)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="1 Column">
|
|
19264
|
+
<div class="flex gap-1 w-full h-4 justify-center px-1">
|
|
19265
|
+
<div class="w-full bg-border-default rounded-sm"></div>
|
|
19266
|
+
</div>
|
|
19267
|
+
</button>
|
|
19268
|
+
<button (click)="applyPreset(node.id, 2)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="2 Columns">
|
|
19269
|
+
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
19270
|
+
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
19271
|
+
<div class="w-1/2 bg-border-default rounded-sm"></div>
|
|
19272
|
+
</div>
|
|
19273
|
+
</button>
|
|
19274
|
+
<button (click)="applyPreset(node.id, 3)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="3 Columns">
|
|
19275
|
+
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
19276
|
+
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
19277
|
+
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
19278
|
+
<div class="w-1/3 bg-border-default rounded-sm"></div>
|
|
19279
|
+
</div>
|
|
19280
|
+
</button>
|
|
19281
|
+
<button (click)="applyPreset(node.id, 4)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="4 Columns">
|
|
19282
|
+
<div class="flex gap-0.5 w-full h-4 px-1">
|
|
19283
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19284
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19285
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19286
|
+
<div class="w-1/4 bg-border-default rounded-sm"></div>
|
|
19287
|
+
</div>
|
|
19288
|
+
</button>
|
|
19289
|
+
<button (click)="applyPreset(node.id, 6)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="6 Columns">
|
|
19290
|
+
<span class="text-[12px] text-text-primary font-medium">6 Col</span>
|
|
19291
|
+
</button>
|
|
19292
|
+
<button (click)="applyPreset(node.id, 12)" class="h-9 border border-border-default rounded hover:bg-slate-50 flex items-center justify-center p-1" title="12 Columns">
|
|
19293
|
+
<span class="text-[12px] text-text-primary font-medium">12 Col</span>
|
|
19294
|
+
</button>
|
|
19295
|
+
</div>
|
|
19296
|
+
<button (click)="addColumn(node.id)" class="w-full h-9 bg-primary-500 text-white rounded-md hover:opacity-90 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
19297
|
+
<lucide-icon name="plus" class="w-4 h-4"></lucide-icon> Add Column
|
|
19298
|
+
</button>
|
|
19299
|
+
</div>
|
|
19300
|
+
}
|
|
19301
|
+
|
|
19302
|
+
@if (node.type === 'col') {
|
|
19303
|
+
<div class="inspector-card bg-surface-default border border-border-default rounded-lg p-4 shadow-sm"
|
|
19304
|
+
[class.opacity-60]="state.isReadOnly()"
|
|
19305
|
+
[class.pointer-events-none]="state.isReadOnly()">
|
|
19306
|
+
<div class="section-title text-[11px] font-semibold text-text-primary opacity-70 uppercase tracking-wide mb-3">Responsive Width (1-12)</div>
|
|
19307
|
+
|
|
19308
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19309
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XS</span>
|
|
19310
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xs" (ngModelChange)="onResponsiveChange(node.id, 'xs', $event)">
|
|
19311
|
+
<option *ngFor="let option of responsiveWidthOptions(false)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19312
|
+
</select>
|
|
19313
|
+
</div>
|
|
18860
19314
|
|
|
18861
|
-
|
|
18862
|
-
|
|
18863
|
-
|
|
18864
|
-
|
|
18865
|
-
|
|
18866
|
-
|
|
18867
|
-
</div>
|
|
19315
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19316
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">SM</span>
|
|
19317
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.sm" (ngModelChange)="onResponsiveChange(node.id, 'sm', $event)">
|
|
19318
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19319
|
+
</select>
|
|
19320
|
+
</div>
|
|
18868
19321
|
|
|
18869
|
-
|
|
18870
|
-
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
18874
|
-
|
|
18875
|
-
</div>
|
|
19322
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19323
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">MD</span>
|
|
19324
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.md" (ngModelChange)="onResponsiveChange(node.id, 'md', $event)">
|
|
19325
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19326
|
+
</select>
|
|
19327
|
+
</div>
|
|
18876
19328
|
|
|
18877
|
-
|
|
18878
|
-
|
|
18879
|
-
|
|
18880
|
-
|
|
18881
|
-
|
|
18882
|
-
|
|
18883
|
-
</div>
|
|
19329
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19330
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">LG</span>
|
|
19331
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.lg" (ngModelChange)="onResponsiveChange(node.id, 'lg', $event)">
|
|
19332
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19333
|
+
</select>
|
|
19334
|
+
</div>
|
|
18884
19335
|
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
</div>
|
|
19336
|
+
<div class="flex items-center gap-2 mb-2">
|
|
19337
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">XL</span>
|
|
19338
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive.xl" (ngModelChange)="onResponsiveChange(node.id, 'xl', $event)">
|
|
19339
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19340
|
+
</select>
|
|
19341
|
+
</div>
|
|
18892
19342
|
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
19343
|
+
<div class="flex items-center gap-2">
|
|
19344
|
+
<span class="text-[12px] w-8 text-text-primary opacity-70 font-medium">2XL</span>
|
|
19345
|
+
<select class="h-8 flex-1 rounded-md border border-border-default bg-white px-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 outline-none" [ngModel]="node.responsive ? node.responsive['2xl'] : undefined" (ngModelChange)="onResponsiveChange(node.id, '2xl', $event)">
|
|
19346
|
+
<option *ngFor="let option of responsiveWidthOptions(true)" [ngValue]="option.value">{{ option.label }}</option>
|
|
19347
|
+
</select>
|
|
19348
|
+
</div>
|
|
19349
|
+
</div>
|
|
18900
19350
|
|
|
18901
|
-
|
|
18902
|
-
|
|
18903
|
-
|
|
18904
|
-
|
|
18905
|
-
|
|
18906
|
-
|
|
18907
|
-
|
|
18908
|
-
|
|
18909
|
-
|
|
18910
|
-
|
|
18911
|
-
|
|
18912
|
-
</ui-tabs>
|
|
19351
|
+
@if (!state.isReadOnly()) {
|
|
19352
|
+
<div class="inspector-card bg-red-50 border border-red-100 rounded-lg p-3">
|
|
19353
|
+
<button (click)="removeColumn(node.id)" class="w-full h-8 text-red-600 hover:text-red-700 flex items-center justify-center gap-2 text-[12px] font-medium transition-colors">
|
|
19354
|
+
<lucide-icon name="trash-2" class="w-4 h-4"></lucide-icon> Remove Column
|
|
19355
|
+
</button>
|
|
19356
|
+
</div>
|
|
19357
|
+
}
|
|
19358
|
+
}
|
|
19359
|
+
</div>
|
|
19360
|
+
}
|
|
19361
|
+
</div>
|
|
18913
19362
|
</ng-container>
|
|
18914
19363
|
</div>
|
|
18915
19364
|
|
|
@@ -20856,9 +21305,9 @@ const BASIC_CONTACT_TEMPLATE = {
|
|
|
20856
21305
|
},
|
|
20857
21306
|
{
|
|
20858
21307
|
"id": "btn_submit",
|
|
20859
|
-
"widgetId": "core.form:
|
|
21308
|
+
"widgetId": "core.form:form-button",
|
|
20860
21309
|
"name": "submit",
|
|
20861
|
-
"type": "
|
|
21310
|
+
"type": "form-button",
|
|
20862
21311
|
"label": "Send message",
|
|
20863
21312
|
"variant": "primary",
|
|
20864
21313
|
"buttonType": "submit",
|
|
@@ -20875,9 +21324,9 @@ const BASIC_CONTACT_TEMPLATE = {
|
|
|
20875
21324
|
},
|
|
20876
21325
|
{
|
|
20877
21326
|
"id": "btn_reset",
|
|
20878
|
-
"widgetId": "core.form:
|
|
21327
|
+
"widgetId": "core.form:form-button",
|
|
20879
21328
|
"name": "reset",
|
|
20880
|
-
"type": "
|
|
21329
|
+
"type": "form-button",
|
|
20881
21330
|
"label": "Reset",
|
|
20882
21331
|
"variant": "secondary",
|
|
20883
21332
|
"buttonType": "reset"
|
|
@@ -21269,9 +21718,9 @@ const RULES_SHIPPING_TEMPLATE = {
|
|
|
21269
21718
|
},
|
|
21270
21719
|
{
|
|
21271
21720
|
"id": "btn_submit",
|
|
21272
|
-
"widgetId": "core.form:
|
|
21721
|
+
"widgetId": "core.form:form-button",
|
|
21273
21722
|
"name": "submit",
|
|
21274
|
-
"type": "
|
|
21723
|
+
"type": "form-button",
|
|
21275
21724
|
"label": "Place order",
|
|
21276
21725
|
"variant": "primary",
|
|
21277
21726
|
"buttonType": "submit",
|
|
@@ -21286,9 +21735,9 @@ const RULES_SHIPPING_TEMPLATE = {
|
|
|
21286
21735
|
},
|
|
21287
21736
|
{
|
|
21288
21737
|
"id": "btn_reset",
|
|
21289
|
-
"widgetId": "core.form:
|
|
21738
|
+
"widgetId": "core.form:form-button",
|
|
21290
21739
|
"name": "reset",
|
|
21291
|
-
"type": "
|
|
21740
|
+
"type": "form-button",
|
|
21292
21741
|
"label": "Reset",
|
|
21293
21742
|
"variant": "secondary",
|
|
21294
21743
|
"buttonType": "reset"
|
|
@@ -21578,9 +22027,9 @@ const DATA_SOURCES_TEMPLATE = {
|
|
|
21578
22027
|
},
|
|
21579
22028
|
{
|
|
21580
22029
|
"id": "btn_submit",
|
|
21581
|
-
"widgetId": "core.form:
|
|
22030
|
+
"widgetId": "core.form:form-button",
|
|
21582
22031
|
"name": "submit",
|
|
21583
|
-
"type": "
|
|
22032
|
+
"type": "form-button",
|
|
21584
22033
|
"label": "Create profile",
|
|
21585
22034
|
"variant": "primary",
|
|
21586
22035
|
"buttonType": "submit"
|
|
@@ -36926,10 +37375,6 @@ const FILE_BASIC_FIELDS = [
|
|
|
36926
37375
|
{ key: 'tooltip', type: 'text', label: 'Tooltip' },
|
|
36927
37376
|
...COMMON_GROUP_FIELDS
|
|
36928
37377
|
];
|
|
36929
|
-
const COMMON_ICON_FIELDS = [
|
|
36930
|
-
{ key: 'prefixIcon', type: 'text', label: 'Prefix Icon (Material Name)' },
|
|
36931
|
-
{ key: 'suffixIcon', type: 'text', label: 'Suffix Icon (Material Name)' }
|
|
36932
|
-
];
|
|
36933
37378
|
const COMMON_APPEARANCE_FIELDS = [
|
|
36934
37379
|
{
|
|
36935
37380
|
key: 'appearance',
|
|
@@ -36964,18 +37409,6 @@ const COMMON_STYLE_SECTIONS = [
|
|
|
36964
37409
|
STYLE_TRANSFORM_SECTION,
|
|
36965
37410
|
STYLE_EFFECTS_SECTION
|
|
36966
37411
|
];
|
|
36967
|
-
const COMMON_VALIDATION_SECTION = {
|
|
36968
|
-
label: 'Validation',
|
|
36969
|
-
fields: [
|
|
36970
|
-
{ key: 'validators', type: 'validators-editor', label: 'Validation Rules' }
|
|
36971
|
-
]
|
|
36972
|
-
};
|
|
36973
|
-
const COMMON_CONDITIONAL_SECTION = {
|
|
36974
|
-
label: 'Conditional',
|
|
36975
|
-
fields: [
|
|
36976
|
-
{ key: 'conditional', type: 'conditional-editor', label: 'Conditional Logic' }
|
|
36977
|
-
]
|
|
36978
|
-
};
|
|
36979
37412
|
// Start with standard sections for Text Field
|
|
36980
37413
|
const BASE_REQUIRED_FIELD = {
|
|
36981
37414
|
key: 'html5.required',
|
|
@@ -36983,67 +37416,25 @@ const BASE_REQUIRED_FIELD = {
|
|
|
36983
37416
|
label: 'Required',
|
|
36984
37417
|
helpText: 'Base required state; Rules can override this dynamically.'
|
|
36985
37418
|
};
|
|
36986
|
-
const
|
|
36987
|
-
|
|
36988
|
-
|
|
36989
|
-
|
|
36990
|
-
|
|
36991
|
-
{ key: 'html5.maxLength', type: 'number', label: 'Max Length' },
|
|
36992
|
-
{ key: 'html5.pattern', type: 'text', label: 'Pattern (regex)' },
|
|
36993
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
36994
|
-
]
|
|
36995
|
-
};
|
|
36996
|
-
const NUMBER_VALIDATION_SECTION = {
|
|
36997
|
-
label: 'Validation',
|
|
36998
|
-
fields: [
|
|
36999
|
-
BASE_REQUIRED_FIELD,
|
|
37000
|
-
{ key: 'html5.min', type: 'number', label: 'Minimum Value' },
|
|
37001
|
-
{ key: 'html5.max', type: 'number', label: 'Maximum Value' },
|
|
37002
|
-
{ key: 'html5.step', type: 'number', label: 'Step (Increment)' },
|
|
37003
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37004
|
-
]
|
|
37005
|
-
};
|
|
37006
|
-
const DATE_VALIDATION_SECTION = {
|
|
37007
|
-
label: 'Validation',
|
|
37008
|
-
fields: [
|
|
37009
|
-
BASE_REQUIRED_FIELD,
|
|
37010
|
-
{ key: 'html5.min', type: 'text', label: 'Earliest Date (YYYY-MM-DD)' },
|
|
37011
|
-
{ key: 'html5.max', type: 'text', label: 'Latest Date (YYYY-MM-DD)' },
|
|
37012
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37013
|
-
]
|
|
37014
|
-
};
|
|
37015
|
-
const TIME_VALIDATION_SECTION = {
|
|
37016
|
-
label: 'Validation',
|
|
37017
|
-
fields: [
|
|
37018
|
-
BASE_REQUIRED_FIELD,
|
|
37019
|
-
{ key: 'html5.min', type: 'text', label: 'Earliest Time (HH:MM)' },
|
|
37020
|
-
{ key: 'html5.max', type: 'text', label: 'Latest Time (HH:MM)' },
|
|
37021
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37022
|
-
]
|
|
37023
|
-
};
|
|
37024
|
-
const DATETIME_VALIDATION_SECTION = {
|
|
37025
|
-
label: 'Validation',
|
|
37026
|
-
fields: [
|
|
37027
|
-
BASE_REQUIRED_FIELD,
|
|
37028
|
-
{ key: 'html5.min', type: 'text', label: 'Earliest (YYYY-MM-DDTHH:MM)' },
|
|
37029
|
-
{ key: 'html5.max', type: 'text', label: 'Latest (YYYY-MM-DDTHH:MM)' },
|
|
37030
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37031
|
-
]
|
|
37032
|
-
};
|
|
37033
|
-
const SELECT_VALIDATION_SECTION = {
|
|
37034
|
-
label: 'Validation',
|
|
37035
|
-
fields: [
|
|
37036
|
-
BASE_REQUIRED_FIELD,
|
|
37037
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37038
|
-
]
|
|
37039
|
-
};
|
|
37040
|
-
const FILE_VALIDATION_SECTION = {
|
|
37041
|
-
label: 'Validation',
|
|
37042
|
-
fields: [
|
|
37043
|
-
BASE_REQUIRED_FIELD,
|
|
37044
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37045
|
-
]
|
|
37419
|
+
const CUSTOM_VALIDATION_RULES_FIELD = {
|
|
37420
|
+
key: 'validation',
|
|
37421
|
+
type: 'validators-editor',
|
|
37422
|
+
label: 'Custom Validation Rules',
|
|
37423
|
+
helpText: 'Use these for field-level validation checks. Use the Rules tab for conditional behaviour.'
|
|
37046
37424
|
};
|
|
37425
|
+
function createValidationSection(...fields) {
|
|
37426
|
+
return {
|
|
37427
|
+
label: 'Validation',
|
|
37428
|
+
fields: [...fields, CUSTOM_VALIDATION_RULES_FIELD]
|
|
37429
|
+
};
|
|
37430
|
+
}
|
|
37431
|
+
const TEXT_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD, { key: 'html5.minLength', type: 'number', label: 'Min Length' }, { key: 'html5.maxLength', type: 'number', label: 'Max Length' }, { key: 'html5.pattern', type: 'text', label: 'Pattern (regex)' });
|
|
37432
|
+
const NUMBER_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD, { key: 'html5.min', type: 'number', label: 'Minimum Value' }, { key: 'html5.max', type: 'number', label: 'Maximum Value' }, { key: 'html5.step', type: 'number', label: 'Step (Increment)' });
|
|
37433
|
+
const DATE_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD, { key: 'html5.min', type: 'text', label: 'Earliest Date (YYYY-MM-DD)' }, { key: 'html5.max', type: 'text', label: 'Latest Date (YYYY-MM-DD)' });
|
|
37434
|
+
const TIME_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD, { key: 'html5.min', type: 'text', label: 'Earliest Time (HH:MM)' }, { key: 'html5.max', type: 'text', label: 'Latest Time (HH:MM)' });
|
|
37435
|
+
const DATETIME_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD, { key: 'html5.min', type: 'text', label: 'Earliest (YYYY-MM-DDTHH:MM)' }, { key: 'html5.max', type: 'text', label: 'Latest (YYYY-MM-DDTHH:MM)' });
|
|
37436
|
+
const SELECT_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD);
|
|
37437
|
+
const FILE_VALIDATION_SECTION = createValidationSection(BASE_REQUIRED_FIELD);
|
|
37047
37438
|
const BUTTON_VARIANT_OPTIONS = [
|
|
37048
37439
|
{ label: 'Primary (Blue)', value: 'primary' },
|
|
37049
37440
|
{ label: 'Secondary (Outline)', value: 'secondary' }
|
|
@@ -37084,7 +37475,6 @@ const IMAGE_BUTTON_PROPERTIES = [
|
|
|
37084
37475
|
];
|
|
37085
37476
|
const TEXT_WIDGET_PROPERTIES = [
|
|
37086
37477
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37087
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37088
37478
|
TEXT_VALIDATION_SECTION,
|
|
37089
37479
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37090
37480
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37115,7 +37505,6 @@ const FILE_WIDGET_PROPERTIES = [
|
|
|
37115
37505
|
]
|
|
37116
37506
|
},
|
|
37117
37507
|
FILE_VALIDATION_SECTION,
|
|
37118
|
-
COMMON_CONDITIONAL_SECTION,
|
|
37119
37508
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37120
37509
|
...COMMON_STYLE_SECTIONS
|
|
37121
37510
|
];
|
|
@@ -37250,9 +37639,7 @@ const FIELD_WIDGETS = [
|
|
|
37250
37639
|
...COMMON_BASIC_FIELDS
|
|
37251
37640
|
]
|
|
37252
37641
|
},
|
|
37253
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37254
37642
|
NUMBER_VALIDATION_SECTION,
|
|
37255
|
-
COMMON_CONDITIONAL_SECTION,
|
|
37256
37643
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37257
37644
|
...COMMON_STYLE_SECTIONS
|
|
37258
37645
|
]
|
|
@@ -37280,7 +37667,6 @@ const FIELD_WIDGETS = [
|
|
|
37280
37667
|
dataBinding: { shape: 'scalar', targetPath: 'defaultValue' },
|
|
37281
37668
|
properties: [
|
|
37282
37669
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37283
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37284
37670
|
DATE_VALIDATION_SECTION,
|
|
37285
37671
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37286
37672
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37309,7 +37695,6 @@ const FIELD_WIDGETS = [
|
|
|
37309
37695
|
dataBinding: { shape: 'scalar', targetPath: 'defaultValue' },
|
|
37310
37696
|
properties: [
|
|
37311
37697
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37312
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37313
37698
|
TIME_VALIDATION_SECTION,
|
|
37314
37699
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37315
37700
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37336,7 +37721,6 @@ const FIELD_WIDGETS = [
|
|
|
37336
37721
|
dataBinding: { shape: 'scalar', targetPath: 'defaultValue' },
|
|
37337
37722
|
properties: [
|
|
37338
37723
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37339
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37340
37724
|
DATETIME_VALIDATION_SECTION,
|
|
37341
37725
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37342
37726
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37366,7 +37750,6 @@ const FIELD_WIDGETS = [
|
|
|
37366
37750
|
dataBinding: { shape: 'scalar', targetPath: 'defaultValue' },
|
|
37367
37751
|
properties: [
|
|
37368
37752
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37369
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37370
37753
|
DATE_VALIDATION_SECTION,
|
|
37371
37754
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37372
37755
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37396,7 +37779,6 @@ const FIELD_WIDGETS = [
|
|
|
37396
37779
|
dataBinding: { shape: 'scalar', targetPath: 'defaultValue' },
|
|
37397
37780
|
properties: [
|
|
37398
37781
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37399
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37400
37782
|
DATE_VALIDATION_SECTION,
|
|
37401
37783
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37402
37784
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37583,7 +37965,6 @@ const FIELD_WIDGETS = [
|
|
|
37583
37965
|
dataBinding: { shape: 'scalar', targetPath: 'defaultValue' },
|
|
37584
37966
|
properties: [
|
|
37585
37967
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37586
|
-
{ label: 'Icons', fields: COMMON_ICON_FIELDS },
|
|
37587
37968
|
NUMBER_VALIDATION_SECTION,
|
|
37588
37969
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37589
37970
|
...COMMON_STYLE_SECTIONS
|
|
@@ -37663,44 +38044,6 @@ const FIELD_WIDGETS = [
|
|
|
37663
38044
|
dataConsumer: 'none',
|
|
37664
38045
|
properties: BUTTON_PROPERTIES
|
|
37665
38046
|
}),
|
|
37666
|
-
defineWidget(pluginId$2, {
|
|
37667
|
-
kind: 'button',
|
|
37668
|
-
flavor: 'form',
|
|
37669
|
-
type: 'submit-button',
|
|
37670
|
-
icon: 'send',
|
|
37671
|
-
label: 'Submit Button',
|
|
37672
|
-
createConfig: () => ({
|
|
37673
|
-
id: generateId$2(),
|
|
37674
|
-
name: 'submit_' + Date.now(),
|
|
37675
|
-
type: 'submit-button',
|
|
37676
|
-
label: 'Submit',
|
|
37677
|
-
variant: 'primary',
|
|
37678
|
-
buttonType: 'submit',
|
|
37679
|
-
style: { width: 'auto' }
|
|
37680
|
-
}),
|
|
37681
|
-
renderer: ButtonWidgetComponent,
|
|
37682
|
-
dataConsumer: 'none',
|
|
37683
|
-
properties: BUTTON_PROPERTIES
|
|
37684
|
-
}),
|
|
37685
|
-
defineWidget(pluginId$2, {
|
|
37686
|
-
kind: 'button',
|
|
37687
|
-
flavor: 'form',
|
|
37688
|
-
type: 'reset-button',
|
|
37689
|
-
icon: 'rotate-ccw',
|
|
37690
|
-
label: 'Reset Button',
|
|
37691
|
-
createConfig: () => ({
|
|
37692
|
-
id: generateId$2(),
|
|
37693
|
-
name: 'reset_' + Date.now(),
|
|
37694
|
-
type: 'reset-button',
|
|
37695
|
-
label: 'Reset',
|
|
37696
|
-
variant: 'secondary',
|
|
37697
|
-
buttonType: 'reset',
|
|
37698
|
-
style: { width: 'auto' }
|
|
37699
|
-
}),
|
|
37700
|
-
renderer: ButtonWidgetComponent,
|
|
37701
|
-
dataConsumer: 'none',
|
|
37702
|
-
properties: BUTTON_PROPERTIES
|
|
37703
|
-
}),
|
|
37704
38047
|
defineWidget(pluginId$2, {
|
|
37705
38048
|
kind: 'button',
|
|
37706
38049
|
flavor: 'form',
|
|
@@ -37758,7 +38101,6 @@ const FIELD_WIDGETS = [
|
|
|
37758
38101
|
},
|
|
37759
38102
|
// Options are now handled in Data Tab
|
|
37760
38103
|
SELECT_VALIDATION_SECTION,
|
|
37761
|
-
COMMON_CONDITIONAL_SECTION,
|
|
37762
38104
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37763
38105
|
...COMMON_STYLE_SECTIONS
|
|
37764
38106
|
]
|
|
@@ -37788,7 +38130,6 @@ const FIELD_WIDGETS = [
|
|
|
37788
38130
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37789
38131
|
// Options handled in Data Tab
|
|
37790
38132
|
SELECT_VALIDATION_SECTION,
|
|
37791
|
-
COMMON_CONDITIONAL_SECTION,
|
|
37792
38133
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37793
38134
|
...COMMON_STYLE_SECTIONS
|
|
37794
38135
|
]
|
|
@@ -37818,7 +38159,6 @@ const FIELD_WIDGETS = [
|
|
|
37818
38159
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37819
38160
|
// Options handled in Data Tab
|
|
37820
38161
|
SELECT_VALIDATION_SECTION,
|
|
37821
|
-
COMMON_CONDITIONAL_SECTION,
|
|
37822
38162
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37823
38163
|
...COMMON_STYLE_SECTIONS
|
|
37824
38164
|
]
|
|
@@ -37843,14 +38183,7 @@ const FIELD_WIDGETS = [
|
|
|
37843
38183
|
properties: [
|
|
37844
38184
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37845
38185
|
// Boolean specific validation or standard
|
|
37846
|
-
|
|
37847
|
-
label: 'Validation',
|
|
37848
|
-
fields: [
|
|
37849
|
-
BASE_REQUIRED_FIELD,
|
|
37850
|
-
{ key: 'validators', type: 'validators-editor', label: 'Advanced Rules' }
|
|
37851
|
-
]
|
|
37852
|
-
},
|
|
37853
|
-
COMMON_CONDITIONAL_SECTION,
|
|
38186
|
+
createValidationSection(BASE_REQUIRED_FIELD),
|
|
37854
38187
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37855
38188
|
...COMMON_STYLE_SECTIONS
|
|
37856
38189
|
]
|
|
@@ -37881,7 +38214,6 @@ const FIELD_WIDGETS = [
|
|
|
37881
38214
|
properties: [
|
|
37882
38215
|
{ label: 'Basic', fields: COMMON_BASIC_FIELDS },
|
|
37883
38216
|
SELECT_VALIDATION_SECTION,
|
|
37884
|
-
COMMON_CONDITIONAL_SECTION,
|
|
37885
38217
|
{ label: 'Appearance', fields: COMMON_APPEARANCE_FIELDS },
|
|
37886
38218
|
...COMMON_STYLE_SECTIONS
|
|
37887
38219
|
]
|
|
@@ -37945,7 +38277,6 @@ const FIELD_WIDGETS = [
|
|
|
37945
38277
|
]
|
|
37946
38278
|
},
|
|
37947
38279
|
...COMMON_STYLE_SECTIONS,
|
|
37948
|
-
COMMON_CONDITIONAL_SECTION
|
|
37949
38280
|
]
|
|
37950
38281
|
})
|
|
37951
38282
|
];
|
|
@@ -40147,6 +40478,162 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
40147
40478
|
args: [DOCUMENT]
|
|
40148
40479
|
}] }] });
|
|
40149
40480
|
|
|
40481
|
+
class UiTabComponent {
|
|
40482
|
+
label = '';
|
|
40483
|
+
name = ''; // Unique key for controlled mode
|
|
40484
|
+
disabled = false;
|
|
40485
|
+
badge;
|
|
40486
|
+
badgeTone = 'neutral';
|
|
40487
|
+
template;
|
|
40488
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
40489
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: UiTabComponent, isStandalone: true, selector: "ui-tab", inputs: { label: "label", name: "name", disabled: "disabled", badge: "badge", badgeTone: "badgeTone" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["tpl"], descendants: true, static: true }], ngImport: i0, template: `<ng-template #tpl><ng-content></ng-content></ng-template>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
40490
|
+
}
|
|
40491
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabComponent, decorators: [{
|
|
40492
|
+
type: Component,
|
|
40493
|
+
args: [{
|
|
40494
|
+
selector: 'ui-tab',
|
|
40495
|
+
standalone: true,
|
|
40496
|
+
imports: [CommonModule],
|
|
40497
|
+
template: `<ng-template #tpl><ng-content></ng-content></ng-template>`
|
|
40498
|
+
}]
|
|
40499
|
+
}], propDecorators: { label: [{
|
|
40500
|
+
type: Input
|
|
40501
|
+
}], name: [{
|
|
40502
|
+
type: Input
|
|
40503
|
+
}], disabled: [{
|
|
40504
|
+
type: Input
|
|
40505
|
+
}], badge: [{
|
|
40506
|
+
type: Input
|
|
40507
|
+
}], badgeTone: [{
|
|
40508
|
+
type: Input
|
|
40509
|
+
}], template: [{
|
|
40510
|
+
type: ViewChild,
|
|
40511
|
+
args: ['tpl', { static: true }]
|
|
40512
|
+
}] } });
|
|
40513
|
+
class UiTabsComponent {
|
|
40514
|
+
tabQuery;
|
|
40515
|
+
activeTab;
|
|
40516
|
+
activeTabChange = new EventEmitter();
|
|
40517
|
+
// Internal state if uncontrolled
|
|
40518
|
+
_internalIndex = 0;
|
|
40519
|
+
tabs = [];
|
|
40520
|
+
ngAfterContentInit() {
|
|
40521
|
+
this.tabs = this.tabQuery.toArray();
|
|
40522
|
+
}
|
|
40523
|
+
isActive(tab) {
|
|
40524
|
+
if (this.activeTab !== undefined) {
|
|
40525
|
+
return this.activeTab === (tab.name || tab.label);
|
|
40526
|
+
}
|
|
40527
|
+
return this.tabs.indexOf(tab) === this._internalIndex;
|
|
40528
|
+
}
|
|
40529
|
+
activate(tab) {
|
|
40530
|
+
if (tab.disabled)
|
|
40531
|
+
return;
|
|
40532
|
+
const key = tab.name || tab.label;
|
|
40533
|
+
if (this.activeTab !== undefined) {
|
|
40534
|
+
this.activeTabChange.emit(key);
|
|
40535
|
+
}
|
|
40536
|
+
else {
|
|
40537
|
+
this._internalIndex = this.tabs.indexOf(tab);
|
|
40538
|
+
}
|
|
40539
|
+
}
|
|
40540
|
+
get activeTemplate() {
|
|
40541
|
+
if (this.tabs.length === 0)
|
|
40542
|
+
return null;
|
|
40543
|
+
let activeTab;
|
|
40544
|
+
if (this.activeTab !== undefined) {
|
|
40545
|
+
activeTab = this.tabs.find(t => (t.name || t.label) === this.activeTab);
|
|
40546
|
+
}
|
|
40547
|
+
else {
|
|
40548
|
+
activeTab = this.tabs[this._internalIndex];
|
|
40549
|
+
}
|
|
40550
|
+
return activeTab?.template || null;
|
|
40551
|
+
}
|
|
40552
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
40553
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: UiTabsComponent, isStandalone: true, selector: "ui-tabs", inputs: { activeTab: "activeTab" }, outputs: { activeTabChange: "activeTabChange" }, queries: [{ propertyName: "tabQuery", predicate: UiTabComponent }], ngImport: i0, template: `
|
|
40554
|
+
<div class="flex flex-col min-h-0 h-full">
|
|
40555
|
+
<div class="flex items-center gap-1 px-3 border-b border-slate-200 bg-white shrink-0">
|
|
40556
|
+
<button
|
|
40557
|
+
*ngFor="let tab of tabs; let i = index"
|
|
40558
|
+
(click)="activate(tab)"
|
|
40559
|
+
class="relative h-10 px-3 text-xs font-semibold transition-colors rounded-t-md border-b-2"
|
|
40560
|
+
[class.text-accent-600]="isActive(tab)"
|
|
40561
|
+
[class.border-accent-600]="isActive(tab)"
|
|
40562
|
+
[class.text-ink-500]="!isActive(tab)"
|
|
40563
|
+
[class.border-transparent]="!isActive(tab)"
|
|
40564
|
+
[class.hover:text-ink-700]="!isActive(tab)"
|
|
40565
|
+
[disabled]="tab.disabled"
|
|
40566
|
+
>
|
|
40567
|
+
<span class="flex items-center gap-2">
|
|
40568
|
+
{{ tab.label }}
|
|
40569
|
+
<span *ngIf="tab.badge" class="text-[10px] px-1.5 py-0.5 rounded-full border"
|
|
40570
|
+
[class.bg-accent-50]="tab.badgeTone === 'accent'"
|
|
40571
|
+
[class.border-accent-200]="tab.badgeTone === 'accent'"
|
|
40572
|
+
[class.text-accent-700]="tab.badgeTone === 'accent'"
|
|
40573
|
+
[class.bg-slate-100]="tab.badgeTone === 'neutral'"
|
|
40574
|
+
[class.border-slate-200]="tab.badgeTone === 'neutral'"
|
|
40575
|
+
[class.text-slate-600]="tab.badgeTone === 'neutral'">
|
|
40576
|
+
{{ tab.badge }}
|
|
40577
|
+
</span>
|
|
40578
|
+
</span>
|
|
40579
|
+
</button>
|
|
40580
|
+
</div>
|
|
40581
|
+
|
|
40582
|
+
<div class="flex-1 min-h-0 overflow-hidden bg-slate-50/30">
|
|
40583
|
+
<ng-container *ngIf="activeTemplate">
|
|
40584
|
+
<ng-container *ngTemplateOutlet="activeTemplate"></ng-container>
|
|
40585
|
+
</ng-container>
|
|
40586
|
+
</div>
|
|
40587
|
+
</div>
|
|
40588
|
+
`, isInline: true, styles: [":host{display:block;height:100%}\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: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
40589
|
+
}
|
|
40590
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: UiTabsComponent, decorators: [{
|
|
40591
|
+
type: Component,
|
|
40592
|
+
args: [{ selector: 'ui-tabs', standalone: true, imports: [CommonModule], template: `
|
|
40593
|
+
<div class="flex flex-col min-h-0 h-full">
|
|
40594
|
+
<div class="flex items-center gap-1 px-3 border-b border-slate-200 bg-white shrink-0">
|
|
40595
|
+
<button
|
|
40596
|
+
*ngFor="let tab of tabs; let i = index"
|
|
40597
|
+
(click)="activate(tab)"
|
|
40598
|
+
class="relative h-10 px-3 text-xs font-semibold transition-colors rounded-t-md border-b-2"
|
|
40599
|
+
[class.text-accent-600]="isActive(tab)"
|
|
40600
|
+
[class.border-accent-600]="isActive(tab)"
|
|
40601
|
+
[class.text-ink-500]="!isActive(tab)"
|
|
40602
|
+
[class.border-transparent]="!isActive(tab)"
|
|
40603
|
+
[class.hover:text-ink-700]="!isActive(tab)"
|
|
40604
|
+
[disabled]="tab.disabled"
|
|
40605
|
+
>
|
|
40606
|
+
<span class="flex items-center gap-2">
|
|
40607
|
+
{{ tab.label }}
|
|
40608
|
+
<span *ngIf="tab.badge" class="text-[10px] px-1.5 py-0.5 rounded-full border"
|
|
40609
|
+
[class.bg-accent-50]="tab.badgeTone === 'accent'"
|
|
40610
|
+
[class.border-accent-200]="tab.badgeTone === 'accent'"
|
|
40611
|
+
[class.text-accent-700]="tab.badgeTone === 'accent'"
|
|
40612
|
+
[class.bg-slate-100]="tab.badgeTone === 'neutral'"
|
|
40613
|
+
[class.border-slate-200]="tab.badgeTone === 'neutral'"
|
|
40614
|
+
[class.text-slate-600]="tab.badgeTone === 'neutral'">
|
|
40615
|
+
{{ tab.badge }}
|
|
40616
|
+
</span>
|
|
40617
|
+
</span>
|
|
40618
|
+
</button>
|
|
40619
|
+
</div>
|
|
40620
|
+
|
|
40621
|
+
<div class="flex-1 min-h-0 overflow-hidden bg-slate-50/30">
|
|
40622
|
+
<ng-container *ngIf="activeTemplate">
|
|
40623
|
+
<ng-container *ngTemplateOutlet="activeTemplate"></ng-container>
|
|
40624
|
+
</ng-container>
|
|
40625
|
+
</div>
|
|
40626
|
+
</div>
|
|
40627
|
+
`, styles: [":host{display:block;height:100%}\n"] }]
|
|
40628
|
+
}], propDecorators: { tabQuery: [{
|
|
40629
|
+
type: ContentChildren,
|
|
40630
|
+
args: [UiTabComponent]
|
|
40631
|
+
}], activeTab: [{
|
|
40632
|
+
type: Input
|
|
40633
|
+
}], activeTabChange: [{
|
|
40634
|
+
type: Output
|
|
40635
|
+
}] } });
|
|
40636
|
+
|
|
40150
40637
|
class AiToolRegistryService {
|
|
40151
40638
|
state;
|
|
40152
40639
|
widgetDefs;
|