@widgetic/editor 4.0.2 โ†’ 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/components/MockWidget.svelte +1 -1
  2. package/dist/components/WidgetPreview.svelte +34 -50
  3. package/dist/components/editors/EmbedEditor.svelte +1 -1
  4. package/dist/components/editors/PropsEditor.svelte +173 -148
  5. package/dist/components/ic/BrowserInputController.svelte +14 -14
  6. package/dist/components/ic/CheckboxInputController.svelte +1 -1
  7. package/dist/components/ic/ColorPickerInputController.svelte +37 -37
  8. package/dist/components/ic/DatePickerInputController.svelte +6 -6
  9. package/dist/components/ic/DropdownInputController.svelte +1 -1
  10. package/dist/components/ic/FontInputController.svelte +136 -63
  11. package/dist/components/ic/FontInputController.svelte.d.ts +3 -1
  12. package/dist/components/ic/NumberInputController.svelte +37 -37
  13. package/dist/components/ic/RadioGroupInputController.svelte +1 -1
  14. package/dist/components/ic/SliderRangeInputController.svelte +1 -1
  15. package/dist/components/ic/SwitchInputController.svelte +1 -1
  16. package/dist/components/ic/TextAreaInputController.svelte +23 -23
  17. package/dist/components/ic/TextAreaPreviewInputController.svelte +2 -2
  18. package/dist/components/ic/VectorInputController.svelte +34 -34
  19. package/dist/components/ic/shared/CategoryTabs.svelte +1 -0
  20. package/dist/components/ic/shared/RecentItemsSection.svelte +21 -6
  21. package/dist/components/ic/shared/RecentItemsSection.svelte.d.ts +1 -0
  22. package/dist/stores/userSession.d.ts +1 -1
  23. package/dist/stores/userSession.js +17 -2
  24. package/dist/utils/FontManager.d.ts +1 -1
  25. package/dist/utils/FontManager.js +75 -102
  26. package/dist/utils/VectorManager.d.ts +3 -1
  27. package/dist/utils/VectorManager.js +30 -70
  28. package/dist/utils/colorTransparency.js +3 -3
  29. package/dist/utils/fontUtils.js +1 -1
  30. package/dist/utils/passiveEvents.d.ts +5 -0
  31. package/dist/utils/passiveEvents.js +9 -18
  32. package/dist/utils/recentColors.js +15 -15
  33. package/dist/utils/vectorUtils.js +1 -1
  34. package/package.json +1 -1
@@ -157,6 +157,18 @@
157
157
  let hasLoggedContent = false; // Prevents duplicate logging of content tab info
158
158
  let designState: Record<string, InputValue> = { ...initialDesignValues }; // Stores design property values
159
159
  let contentState: Record<string, InputValue> = { ...initialContentValues }; // Stores content property values
160
+
161
+ let prevInitialDesignValues = initialDesignValues;
162
+ $: if (initialDesignValues !== prevInitialDesignValues) {
163
+ prevInitialDesignValues = initialDesignValues;
164
+ designState = { ...initialDesignValues };
165
+ }
166
+
167
+ let prevInitialContentValues = initialContentValues;
168
+ $: if (initialContentValues !== prevInitialContentValues) {
169
+ prevInitialContentValues = initialContentValues;
170
+ contentState = { ...initialContentValues };
171
+ }
160
172
  let isGenericContentOpen = true; // Controls generic content section visibility
161
173
  let lastFocusedDesignController: string | null = null; // Tracks last focused design input
162
174
  let lastFocusedContentController: string | null = null; // Tracks last focused content input
@@ -226,7 +238,7 @@
226
238
  }
227
239
 
228
240
  if (keysToRemove.length > 0) {
229
- console.log('๐Ÿงน [PropsEditor] Clearing font weight states on init:', keysToRemove);
241
+ // console.log('๐Ÿงน [PropsEditor] Clearing font weight states on init:', keysToRemove);
230
242
  keysToRemove.forEach(key => localStorage.removeItem(key));
231
243
  }
232
244
  }
@@ -275,26 +287,8 @@
275
287
  // Initialize FontManager
276
288
  const initializeEditor = async () => {
277
289
  try {
278
- // console.log('๐Ÿš€ [PropsEditor] Starting initialization...', {
279
- // hasDesignSchema: !!designSchema,
280
- // hasContentSchema: !!contentSchema
281
- // });
282
-
283
- // Initialize FontManager when PropsEditor mounts
284
- // console.log('๐Ÿ“š [PropsEditor] Initializing FontManager...');
285
- const fontManagerInstance = await FontManager.getInstance(appConfig.GOOGLE_FONTS_API_KEY);
286
- // console.log('โœ… [PropsEditor] FontManager initialized');
287
-
288
- // Preload the "Mine" category fonts to prevent loading delay in FontInputController instances
289
- try {
290
- const customFonts = await fontManagerInstance.loadCustomFonts();
291
- console.log('โœ… [PropsEditor] Preloaded "Mine" category fonts:', {
292
- count: customFonts.length,
293
- fonts: customFonts.slice(0, 3).map(f => f.family)
294
- });
295
- } catch (error) {
296
- console.error('โŒ [PropsEditor] Failed to preload "Mine" category fonts:', error);
297
- }
290
+ // Initialize FontManager in background without blocking editor startup
291
+ void FontManager.getInstance(appConfig.GOOGLE_FONTS_API_KEY);
298
292
 
299
293
  // Log design tab info if schema exists
300
294
  if (designSchema && designSchema[0]?.components && !hasLoggedDesign) {
@@ -507,7 +501,7 @@
507
501
 
508
502
  // Update event handlers
509
503
  currentDraggable.on('drag:start', (event: any) => {
510
- console.log('[Draggable] drag:start event');
504
+ // console.log('[Draggable] drag:start event');
511
505
  isDragging = true; // Set flag immediately to prevent afterUpdate interference
512
506
 
513
507
  const dragHandle = event.originalSource?.querySelector('.drag-handle');
@@ -577,7 +571,7 @@
577
571
  if (deltaX > dragThreshold || deltaY > dragThreshold) {
578
572
  isDragStarted = true;
579
573
  // isDragging = true; - This is now set in drag:start
580
- console.log('[Draggable] isDragStarted set to true');
574
+ // console.log('[Draggable] isDragStarted set to true');
581
575
 
582
576
  requestAnimationFrame(() => {
583
577
  const mirror = document.querySelector('.draggable-mirror');
@@ -705,7 +699,7 @@
705
699
  });
706
700
 
707
701
  currentDraggable.on('sortable:sorted', (event: { newIndex: number; oldIndex: number }) => {
708
- console.log('[Draggable] sortable:sorted event fired', { oldIndex: event.oldIndex, newIndex: event.newIndex });
702
+ // console.log('[Draggable] sortable:sorted event fired', { oldIndex: event.oldIndex, newIndex: event.newIndex });
709
703
  try {
710
704
  const { oldIndex, newIndex } = event;
711
705
 
@@ -718,7 +712,7 @@
718
712
 
719
713
  // No need to do anything if the item was dropped in the same place
720
714
  if (oldIndex === newIndex) {
721
- console.log('[Drag] Item dropped in the same position. No change needed.');
715
+ // console.log('[Drag] Item dropped in the same position. No change needed.');
722
716
  isDragStarted = false;
723
717
  return;
724
718
  }
@@ -728,7 +722,7 @@
728
722
  isDragStarted = false;
729
723
  return;
730
724
  }
731
- console.log('[Drag] Before:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
725
+ // console.log('[Drag] Before:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
732
726
 
733
727
  const items = [...contentSchema.contentItems];
734
728
  const [movedItem] = items.splice(oldIndex, 1);
@@ -749,7 +743,7 @@
749
743
 
750
744
  const renumbered = renumberAutoItemTitles(items);
751
745
  contentSchema = { ...contentSchema, contentItems: renumbered };
752
- console.log('[Drag] After (reordered with indices):', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
746
+ // console.log('[Drag] After (reordered with indices):', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
753
747
  dispatch('updated', { contentSchema });
754
748
  dispatchContentItemsChanged(contentSchema.contentItems);
755
749
 
@@ -887,7 +881,7 @@
887
881
  }
888
882
  if (needsUpdate) {
889
883
  contentState = { ...contentState, ...patch };
890
- console.log('[PropsEditor] Initialized content item state keys:', Object.keys(patch));
884
+ // console.log('[PropsEditor] Initialized content item state keys:', Object.keys(patch));
891
885
  }
892
886
  }
893
887
 
@@ -1026,63 +1020,61 @@
1026
1020
  * @param opacity - Optional opacity value for color properties
1027
1021
  */
1028
1022
  function updateState(schema: string, propertyId: string, value: InputValue, opacity?: number) {
1029
- requestAnimationFrame(() => {
1030
- if (schema === 'design') {
1031
- const newState = { ...designState };
1032
- newState[propertyId] = value;
1033
- if (opacity !== undefined) {
1034
- newState[`${propertyId}_opacity`] = opacity;
1035
- }
1036
- designState = newState;
1037
- } else {
1038
- const newState = { ...contentState };
1039
- newState[propertyId] = value;
1040
- if (opacity !== undefined) {
1041
- newState[`${propertyId}_opacity`] = opacity;
1042
- }
1043
- contentState = newState;
1044
-
1045
- // For content item properties (keyed as "itemId__propName"), also update item.properties[].value
1046
- if (propertyId.includes('__') && Array.isArray(contentSchema?.contentItems)) {
1047
- const [itemId, basePropName] = propertyId.split('__');
1048
- const item = contentSchema.contentItems.find((i: ContentItem) => i.id === itemId);
1049
- if (item) {
1050
- const prop = item.properties.find((p: any) => (p.id || p.name) === basePropName);
1051
- if (prop) prop.value = value;
1052
-
1053
- // Update the collapsible header title when a "title"-like property changes
1054
- const propName = (basePropName || '').toLowerCase();
1055
- if (propName.includes('title') || propName.includes('name') || propName.includes('label')) {
1056
- if (typeof value === 'string' && value.trim()) {
1057
- item.title = value;
1058
- contentSchema = contentSchema; // trigger Svelte reactivity
1059
- }
1023
+ if (schema === 'design') {
1024
+ const newState = { ...designState };
1025
+ newState[propertyId] = value;
1026
+ if (opacity !== undefined) {
1027
+ newState[`${propertyId}_opacity`] = opacity;
1028
+ }
1029
+ designState = newState;
1030
+ } else {
1031
+ const newState = { ...contentState };
1032
+ newState[propertyId] = value;
1033
+ if (opacity !== undefined) {
1034
+ newState[`${propertyId}_opacity`] = opacity;
1035
+ }
1036
+ contentState = newState;
1037
+
1038
+ // For content item properties (keyed as "itemId__propName"), also update item.properties[].value
1039
+ if (propertyId.includes('__') && Array.isArray(contentSchema?.contentItems)) {
1040
+ const [itemId, basePropName] = propertyId.split('__');
1041
+ const item = contentSchema.contentItems.find((i: ContentItem) => i.id === itemId);
1042
+ if (item) {
1043
+ const prop = item.properties.find((p: any) => (p.id || p.name) === basePropName);
1044
+ if (prop) prop.value = value;
1045
+
1046
+ // Update the collapsible header title when a "title"-like property changes
1047
+ const propName = (basePropName || '').toLowerCase();
1048
+ if (propName.includes('title') || propName.includes('name') || propName.includes('label')) {
1049
+ if (typeof value === 'string' && value.trim()) {
1050
+ item.title = value;
1051
+ contentSchema = contentSchema; // trigger Svelte reactivity
1060
1052
  }
1061
1053
  }
1062
1054
  }
1063
1055
  }
1056
+ }
1064
1057
 
1065
- // Dispatch with both composite key and item context for parent to handle
1066
- let itemId: string | undefined;
1067
- let originalPropertyId = propertyId;
1068
- if (schema === 'content' && propertyId.includes('__')) {
1069
- [itemId, originalPropertyId] = propertyId.split('__');
1070
- }
1071
-
1072
- dispatch('propertyChange', { schema, propertyId: originalPropertyId, value, opacity, itemId });
1058
+ // Dispatch with both composite key and item context for parent to handle
1059
+ let itemId: string | undefined;
1060
+ let originalPropertyId = propertyId;
1061
+ if (schema === 'content' && propertyId.includes('__')) {
1062
+ [itemId, originalPropertyId] = propertyId.split('__');
1063
+ }
1064
+
1065
+ dispatch('propertyChange', { schema, propertyId: originalPropertyId, value, opacity, itemId });
1073
1066
 
1074
- if (schema === 'content' && itemId && Array.isArray(contentSchema?.contentItems)) {
1075
- dispatchContentItemsChanged(contentSchema.contentItems);
1076
- }
1067
+ if (schema === 'content' && itemId && Array.isArray(contentSchema?.contentItems)) {
1068
+ dispatchContentItemsChanged(contentSchema.contentItems);
1069
+ }
1077
1070
 
1078
- // When editing a content item property, navigate widget to that item
1079
- if (itemId) {
1080
- const itemIndex = getContentItemIndex(itemId);
1081
- if (itemIndex >= 0) {
1082
- dispatch('goToItem', { index: itemIndex });
1083
- }
1071
+ // When editing a content item property, navigate widget to that item
1072
+ if (itemId) {
1073
+ const itemIndex = getContentItemIndex(itemId);
1074
+ if (itemIndex >= 0) {
1075
+ dispatch('goToItem', { index: itemIndex });
1084
1076
  }
1085
- });
1077
+ }
1086
1078
  }
1087
1079
 
1088
1080
  function getContentItemsMax(): number | null {
@@ -1137,10 +1129,10 @@
1137
1129
  lastFocusedContentController = controllerId;
1138
1130
  }
1139
1131
 
1140
- console.log(`Controller focused in ${currentTab} tab:`, {
1141
- controllerId,
1142
- ...controllerInfo
1143
- });
1132
+ // console.log(`Controller focused in ${currentTab} tab:`, {
1133
+ // controllerId,
1134
+ // ...controllerInfo
1135
+ // });
1144
1136
  }
1145
1137
  }
1146
1138
 
@@ -1153,12 +1145,12 @@
1153
1145
  const currentValue = tab ?? getActiveTab();
1154
1146
  const previousTab = currentTab;
1155
1147
 
1156
- console.log('๐Ÿ”„ [PropsEditor] Tab Change:', {
1157
- from: previousTab,
1158
- to: currentValue,
1159
- hasContentSchema: !!contentSchema,
1160
- isInitialLoad
1161
- });
1148
+ // console.log('๐Ÿ”„ [PropsEditor] Tab Change:', {
1149
+ // from: previousTab,
1150
+ // to: currentValue,
1151
+ // hasContentSchema: !!contentSchema,
1152
+ // isInitialLoad
1153
+ // });
1162
1154
 
1163
1155
  // Update tab state
1164
1156
  currentTab = currentValue;
@@ -1168,16 +1160,16 @@
1168
1160
 
1169
1161
  // Only proceed with content-related operations if contentSchema exists
1170
1162
  if (currentValue === 'content' && !contentSchema) {
1171
- console.log('โ„น๏ธ [PropsEditor] Content tab selected but no content schema available');
1163
+ // console.log('โ„น๏ธ [PropsEditor] Content tab selected but no content schema available');
1172
1164
  return;
1173
1165
  }
1174
1166
 
1175
1167
  // Only log state if content exists
1176
1168
  if (contentSchema) {
1177
- console.log('๐Ÿ’พ Storing', currentValue, 'tab state:', {
1178
- openItems: Array.from(openItems),
1179
- openAccordion: currentValue === 'design' ? designOpenAccordion : contentOpenAccordion
1180
- });
1169
+ // console.log('๐Ÿ’พ Storing', currentValue, 'tab state:', {
1170
+ // openItems: Array.from(openItems),
1171
+ // openAccordion: currentValue === 'design' ? designOpenAccordion : contentOpenAccordion
1172
+ // });
1181
1173
  }
1182
1174
 
1183
1175
  // First find and remove all modal-related elements, but preserve draggable
@@ -1198,15 +1190,15 @@
1198
1190
  '.command-dialog'
1199
1191
  ].join(','));
1200
1192
 
1201
- console.log('๐Ÿงน Cleaning up modals:', {
1202
- count: modalElements.length,
1203
- elements: Array.from(modalElements).map(el => ({
1204
- className: el.className,
1205
- role: el.getAttribute('role'),
1206
- state: el.getAttribute('data-state'),
1207
- side: el.getAttribute('data-side')
1208
- }))
1209
- });
1193
+ // console.log('๐Ÿงน Cleaning up modals:', {
1194
+ // count: modalElements.length,
1195
+ // elements: Array.from(modalElements).map(el => ({
1196
+ // className: el.className,
1197
+ // role: el.getAttribute('role'),
1198
+ // state: el.getAttribute('data-state'),
1199
+ // side: el.getAttribute('data-side')
1200
+ // }))
1201
+ // });
1210
1202
 
1211
1203
  // Remove each modal immediately, but protect scroll-related and draggable elements
1212
1204
  modalElements.forEach(element => {
@@ -1236,7 +1228,7 @@
1236
1228
  // Clear the dropdowns store
1237
1229
  const currentDropdowns = get(openDropdowns);
1238
1230
  if (currentDropdowns.size > 0) {
1239
- console.log('๐Ÿ—‘๏ธ Clearing dropdowns:', Array.from(currentDropdowns));
1231
+ // console.log('๐Ÿ—‘๏ธ Clearing dropdowns:', Array.from(currentDropdowns));
1240
1232
  }
1241
1233
  openDropdowns.set(new Set());
1242
1234
 
@@ -1254,7 +1246,7 @@
1254
1246
  if (currentValue === 'content' && contentSchema) {
1255
1247
  // Wait for tab content to be rendered
1256
1248
  setTimeout(async () => {
1257
- console.log('๐ŸŽฏ Checking draggable state in content tab');
1249
+ // console.log('๐ŸŽฏ Checking draggable state in content tab');
1258
1250
 
1259
1251
  // Check if draggable needs initialization
1260
1252
  const containers = document.querySelectorAll('.content-items');
@@ -1264,10 +1256,10 @@
1264
1256
  !document.querySelector('.draggable-container');
1265
1257
 
1266
1258
  if (needsInit) {
1267
- console.log('๐Ÿ”„ Reinitializing draggable');
1259
+ // console.log('๐Ÿ”„ Reinitializing draggable');
1268
1260
  await initializeDraggable();
1269
1261
  } else {
1270
- console.log('โœ… Draggable already initialized and working');
1262
+ // console.log('โœ… Draggable already initialized and working');
1271
1263
  }
1272
1264
  }, 50);
1273
1265
  }
@@ -1278,10 +1270,10 @@
1278
1270
 
1279
1271
  // Only log if content exists
1280
1272
  if (contentSchema) {
1281
- console.log('๐Ÿ”„ Restoring state for', currentValue, 'tab:', {
1282
- openItems: Array.from(openItems),
1283
- accordionToOpen
1284
- });
1273
+ // console.log('๐Ÿ”„ Restoring state for', currentValue, 'tab:', {
1274
+ // openItems: Array.from(openItems),
1275
+ // accordionToOpen
1276
+ // });
1285
1277
  }
1286
1278
 
1287
1279
  // Restore accordion states after a short delay to ensure DOM is ready
@@ -1294,7 +1286,7 @@
1294
1286
  }
1295
1287
  }
1296
1288
  if (itemsToOpen.length > 0) {
1297
- console.log('๐Ÿ“‚ Opened accordions:', itemsToOpen);
1289
+ // console.log('๐Ÿ“‚ Opened accordions:', itemsToOpen);
1298
1290
  }
1299
1291
  }, 50);
1300
1292
 
@@ -1305,7 +1297,7 @@
1305
1297
  : lastFocusedContentController;
1306
1298
 
1307
1299
  if (controllerToFocus) {
1308
- console.log('๐ŸŽฏ Focusing last focused controller:', controllerToFocus);
1300
+ // console.log('๐ŸŽฏ Focusing last focused controller:', controllerToFocus);
1309
1301
  activeControllerId = controllerToFocus;
1310
1302
  focusController(controllerToFocus);
1311
1303
  } else {
@@ -1316,7 +1308,7 @@
1316
1308
  if (firstController) {
1317
1309
  const id = firstController.getAttribute('id');
1318
1310
  if (id) {
1319
- console.log('๐ŸŽฏ Focusing first controller:', id);
1311
+ // console.log('๐ŸŽฏ Focusing first controller:', id);
1320
1312
  activeControllerId = id;
1321
1313
  focusController(id);
1322
1314
  }
@@ -1329,6 +1321,16 @@
1329
1321
  * Input Controller Management
1330
1322
  * Handles rendering and configuration of different input types
1331
1323
  */
1324
+ function fontIcVisibleLabel(propertyId: string, schemaLabel?: string, description?: string): string {
1325
+ const fromSchema = String(schemaLabel || '').trim();
1326
+ if (fromSchema) return fromSchema;
1327
+ const trimmed = String(description || '').trim();
1328
+ if (trimmed && !/^(titleFont|subtitleFont|headingFont|descriptionFont|font|titeFont)$/i.test(trimmed)) {
1329
+ return trimmed;
1330
+ }
1331
+ return '';
1332
+ }
1333
+
1332
1334
  function renderInputController(schema: string, property: any, propertyIndex: number, isFirstGroup: boolean, contentItemId?: string) {
1333
1335
  const basePropertyId = property.id || property.name;
1334
1336
  const propertyId = contentItemId ? `${contentItemId}__${basePropertyId}` : basePropertyId;
@@ -1386,7 +1388,7 @@
1386
1388
  portalTarget,
1387
1389
  ...restInputController,
1388
1390
  ...(String(inputController.type || '').toLowerCase() === 'font'
1389
- ? { label: description || propertyId || '' }
1391
+ ? { label: fontIcVisibleLabel(propertyId, label, description) }
1390
1392
  : {}),
1391
1393
  ...property.constraints,
1392
1394
  ...additionalProps,
@@ -1396,10 +1398,10 @@
1396
1398
  toggleDropdown: (id: string) => {
1397
1399
  const currentSet = get(openDropdowns);
1398
1400
  if (currentSet.has(id)) {
1399
- console.log(`[toggleDropdown] CLOSING ${id}`);
1401
+ // console.log(`[toggleDropdown] CLOSING ${id}`);
1400
1402
  openDropdowns.set(new Set());
1401
1403
  } else {
1402
- console.log(`[toggleDropdown] OPENING ${id} (closing all others)`);
1404
+ // console.log(`[toggleDropdown] OPENING ${id} (closing all others)`);
1403
1405
  openDropdowns.set(new Set([id]));
1404
1406
  }
1405
1407
  },
@@ -1429,7 +1431,9 @@
1429
1431
  'data-visibility-dependent': hasVisibilityCondition
1430
1432
  },
1431
1433
  header: {
1432
- label: description || propertyId,
1434
+ label: String(inputController.type || '').toLowerCase() === 'font'
1435
+ ? fontIcVisibleLabel(propertyId, label, description)
1436
+ : (description || propertyId),
1433
1437
  helpText: inputController.helpText
1434
1438
  }
1435
1439
  };
@@ -1479,7 +1483,7 @@
1479
1483
  * Used when changing tabs or when scroll events occur
1480
1484
  */
1481
1485
  function closeAllDropdowns() {
1482
- console.log('Closing all dropdowns');
1486
+ // console.log('Closing all dropdowns');
1483
1487
  openDropdowns.set(new Set());
1484
1488
  }
1485
1489
 
@@ -1543,7 +1547,7 @@
1543
1547
  * @param itemId - Identifier for the content item to toggle
1544
1548
  */
1545
1549
  function toggleItem(itemId: string) {
1546
- console.log('๐Ÿ”„ Toggling item:', itemId, 'Current state:', openItems.has(itemId));
1550
+ // console.log('๐Ÿ”„ Toggling item:', itemId, 'Current state:', openItems.has(itemId));
1547
1551
 
1548
1552
  if (openItems.has(itemId)) {
1549
1553
  openItems.delete(itemId);
@@ -1563,11 +1567,11 @@
1563
1567
  openItems = new Set(openItems);
1564
1568
  previouslyOpen = new Set(previouslyOpen);
1565
1569
 
1566
- console.log('โœ… New state:', {
1567
- isOpen: openItems.has(itemId),
1568
- openItems: Array.from(openItems),
1569
- previouslyOpen: Array.from(previouslyOpen)
1570
- });
1570
+ // console.log('โœ… New state:', {
1571
+ // isOpen: openItems.has(itemId),
1572
+ // openItems: Array.from(openItems),
1573
+ // previouslyOpen: Array.from(previouslyOpen)
1574
+ // });
1571
1575
  }
1572
1576
 
1573
1577
  /** Returns the index of a content item by its id, or -1 if not found */
@@ -1632,25 +1636,25 @@
1632
1636
  * Controls input focus behavior and tab switching
1633
1637
  */
1634
1638
  function focusController(controllerId: string) {
1635
- console.log('Attempting to focus controller:', controllerId);
1639
+ // console.log('Attempting to focus controller:', controllerId);
1636
1640
  activeControllerId = controllerId;
1637
1641
  const element = document.getElementById(controllerId);
1638
1642
  if (element) {
1639
1643
  const componentInstance = element.querySelector(':scope > *');
1640
1644
  if (componentInstance && 'focus' in componentInstance) {
1641
- console.log('Calling focus method on component');
1645
+ // console.log('Calling focus method on component');
1642
1646
  (componentInstance as any).focus();
1643
1647
  } else {
1644
1648
  const input = element.querySelector('input, textarea, [role="slider"], button');
1645
1649
  if (input instanceof HTMLElement) {
1646
- console.log('Found focusable element:', input);
1650
+ // console.log('Found focusable element:', input);
1647
1651
  input.focus();
1648
1652
  } else {
1649
- console.log('No focusable element found in controller');
1653
+ // console.log('No focusable element found in controller');
1650
1654
  }
1651
1655
  }
1652
1656
  } else {
1653
- console.log('Controller element not found:', controllerId);
1657
+ // console.log('Controller element not found:', controllerId);
1654
1658
  }
1655
1659
  }
1656
1660
 
@@ -1675,7 +1679,7 @@
1675
1679
  contentSchema.contentItems.forEach((item: ContentItem) => {
1676
1680
  if (item.id) {
1677
1681
  openItems.add(item.id);
1678
- console.log("Added content item:", item.id);
1682
+ // console.log("Added content item:", item.id);
1679
1683
  }
1680
1684
  });
1681
1685
  } else {
@@ -1877,7 +1881,7 @@
1877
1881
  return;
1878
1882
  }
1879
1883
  // Log before add
1880
- console.log('[Add] Before:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
1884
+ // console.log('[Add] Before:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
1881
1885
  // Generate a unique ID for the new item
1882
1886
  let uniqueId: string;
1883
1887
  do {
@@ -1920,8 +1924,8 @@
1920
1924
  dispatch('goToItem', { index: newItemIndex });
1921
1925
  }
1922
1926
  // Log after add
1923
- console.log('[Add] After (should be at end):', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
1924
- console.log('[Add] New item added:', newItem);
1927
+ // console.log('[Add] After (should be at end):', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
1928
+ // console.log('[Add] New item added:', newItem);
1925
1929
 
1926
1930
  // Ensure DOM order matches array order after adding new item
1927
1931
  setTimeout(() => {
@@ -2051,7 +2055,7 @@
2051
2055
  }
2052
2056
  return { id: item.id, title: item.title, ...props };
2053
2057
  });
2054
- console.log('[PropsEditor] Dispatching contentItemsChanged:', serialized.length, 'items');
2058
+ // console.log('[PropsEditor] Dispatching contentItemsChanged:', serialized.length, 'items');
2055
2059
  dispatch('contentItemsChanged', { items: serialized });
2056
2060
  }
2057
2061
 
@@ -2068,7 +2072,7 @@
2068
2072
  }
2069
2073
 
2070
2074
  // Log before deletion
2071
- console.log('[Delete] Before:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
2075
+ // console.log('[Delete] Before:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
2072
2076
  const deletedIndex = contentSchema.contentItems.findIndex((i: ContentItem) => i.id === itemId);
2073
2077
  const initialLength = contentSchema.contentItems.length;
2074
2078
  contentSchema.contentItems = contentSchema.contentItems.filter((i: ContentItem) => i.id !== itemId);
@@ -2080,7 +2084,7 @@
2080
2084
  console.warn('๐Ÿค” No item found with ID:', itemId);
2081
2085
  } else {
2082
2086
  // Log after deletion
2083
- console.log('[Delete] After:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
2087
+ // console.log('[Delete] After:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
2084
2088
  // Notify parent about the updated items list
2085
2089
  dispatch('updated', { contentSchema });
2086
2090
  dispatchContentItemsChanged(contentSchema.contentItems);
@@ -2090,7 +2094,7 @@
2090
2094
  dispatch('goToItem', { index: targetIndex });
2091
2095
  }
2092
2096
  setTimeout(() => {
2093
- console.log('๐Ÿ”„ Reinitializing draggable after deletion');
2097
+ // console.log('๐Ÿ”„ Reinitializing draggable after deletion');
2094
2098
  initializeDraggable();
2095
2099
  }, 0);
2096
2100
  }
@@ -2155,13 +2159,13 @@
2155
2159
  // Initialize the correct tab based on schema availability
2156
2160
  const initialTab = getActiveTab();
2157
2161
  if (initialTab === 'content' && contentSchema) {
2158
- console.log('๐ŸŽฏ Initializing content tab as default');
2162
+ // console.log('๐ŸŽฏ Initializing content tab as default');
2159
2163
  currentTab = 'content';
2160
2164
 
2161
2165
  // Wait for DOM to be ready
2162
2166
  setTimeout(async () => {
2163
2167
  try {
2164
- console.log('๐Ÿ”„ Initializing draggable for content tab');
2168
+ // console.log('๐Ÿ”„ Initializing draggable for content tab');
2165
2169
  await initializeDraggable();
2166
2170
 
2167
2171
  // Set initial states
@@ -2236,7 +2240,7 @@
2236
2240
  const newTab = getActiveTab();
2237
2241
  if (defaultTab !== newTab) {
2238
2242
  defaultTab = newTab;
2239
- console.log('๐Ÿ“‘ [PropsEditor] Updated defaultTab:', { from: defaultTab, to: newTab, hasDesignSchema: !!designSchema, hasContentSchema: !!contentSchema });
2243
+ // console.log('๐Ÿ“‘ [PropsEditor] Updated defaultTab:', { from: defaultTab, to: newTab, hasDesignSchema: !!designSchema, hasContentSchema: !!contentSchema });
2240
2244
  }
2241
2245
  }
2242
2246
 
@@ -2308,7 +2312,7 @@
2308
2312
 
2309
2313
  // Add a reactive log after render to show the current array order and titles
2310
2314
  $: if (contentSchema && Array.isArray(contentSchema?.contentItems)) {
2311
- console.log('[Render] Current contentItems order:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
2315
+ // console.log('[Render] Current contentItems order:', contentSchema.contentItems.map((i: ContentItem) => ({ id: i.id, title: i.title })));
2312
2316
  }
2313
2317
 
2314
2318
  /** Safe accessor โ€” always returns an array even when contentSchema.contentItems is missing or not an array */
@@ -2324,7 +2328,7 @@
2324
2328
  // Helper: log DOM visual order for debugging
2325
2329
  function logOrder(label: string) {
2326
2330
  const titles = Array.from(document.querySelectorAll('.content-item .content-title')).map(el => el.textContent?.trim());
2327
- console.log(`[Order-check] ${label}:`, titles);
2331
+ // console.log(`[Order-check] ${label}:`, titles);
2328
2332
  const transforms = Array.from(document.querySelectorAll('.content-item')).map(el => ({ id: (el as HTMLElement).dataset.id, transform: (el as HTMLElement).style.transform }));
2329
2333
  console.table(transforms);
2330
2334
  }
@@ -2393,9 +2397,9 @@
2393
2397
  >
2394
2398
  <Tabs.Trigger
2395
2399
  value="design"
2396
- class="body flex-1 h-full rounded-[11px] transition-colors duration-250 text-grey5 hover:text-grey7 hover:underline data-[state=active]:bg-white data-[state=active]:text-grey7 data-[state=active]:hover:text-grey7"
2400
+ class="flex-1 h-full rounded-[11px] transition-colors duration-250 text-grey5 hover:text-grey7 hover:underline data-[state=active]:bg-white data-[state=active]:text-grey7 data-[state=active]:hover:text-grey7"
2397
2401
  >
2398
- {designTabTitle}
2402
+ <span class="body">{designTabTitle}</span>
2399
2403
  </Tabs.Trigger>
2400
2404
  {#if contentSchema}
2401
2405
  <Tabs.Trigger
@@ -2403,9 +2407,9 @@
2403
2407
  initializeDraggable();
2404
2408
  }}
2405
2409
  value="content"
2406
- class="body flex-1 h-full rounded-[11px] transition-colors duration-250 text-grey5 hover:text-grey7 hover:underline data-[state=active]:bg-white data-[state=active]:text-grey7 data-[state=active]:hover:text-grey7"
2410
+ class="flex-1 h-full rounded-[11px] transition-colors duration-250 text-grey5 hover:text-grey7 hover:underline data-[state=active]:bg-white data-[state=active]:text-grey7 data-[state=active]:hover:text-grey7"
2407
2411
  >
2408
- {contentTabTitle}
2412
+ <span class="body">{contentTabTitle}</span>
2409
2413
  </Tabs.Trigger>
2410
2414
  {/if}
2411
2415
  </Tabs.List>
@@ -2473,7 +2477,7 @@
2473
2477
  {#if isVisible}
2474
2478
  {@const isFontIc = property.inputController.type.toLowerCase() === 'font'}
2475
2479
  <div
2476
- class="ictrl input-controller flex {isFontIc ? 'flex-col items-stretch' : 'items-center justify-between'} w-full p-0"
2480
+ class="ictrl input-controller flex {isFontIc ? 'font-ic-host flex-col items-stretch' : 'items-center justify-between'} w-full p-0"
2477
2481
  data-state={$openDropdowns?.has(props.controllerId) ? 'open' : 'closed'}
2478
2482
  class:double-height={isFontIc}
2479
2483
  class:position-height={property.inputController.type.toLowerCase() === 'position'}
@@ -2568,6 +2572,7 @@
2568
2572
  {/if}
2569
2573
 
2570
2574
  <Collapsible.Content>
2575
+ {#if isGenericContentOpen}
2571
2576
  <Card.Content class="p-0 px-4">
2572
2577
  <div class="pt-[14px] pb-[16px]">
2573
2578
  <div class="properties-list flex flex-col" style="gap: 8px;">
@@ -2585,7 +2590,7 @@
2585
2590
 
2586
2591
  {#if isVisible}
2587
2592
  {@const isFontIc = property.inputController.type.toLowerCase() === 'font'}
2588
- <div class="ictrl input-controller flex {isFontIc ? 'flex-col items-stretch' : 'items-center justify-between'} w-full p-0 browser-input-wrapper"
2593
+ <div class="ictrl input-controller flex {isFontIc ? 'font-ic-host flex-col items-stretch' : 'items-center justify-between'} w-full p-0 browser-input-wrapper"
2589
2594
  class:double-height={isFontIc}
2590
2595
  >
2591
2596
  {#if !isFontIc && InputComponent !== BrowserInputController}
@@ -2616,6 +2621,7 @@
2616
2621
  </div>
2617
2622
  </div>
2618
2623
  </Card.Content>
2624
+ {/if}
2619
2625
  </Collapsible.Content>
2620
2626
  </Collapsible.Root>
2621
2627
  </Card.Root>
@@ -2666,6 +2672,7 @@
2666
2672
  {/if}
2667
2673
 
2668
2674
  <Collapsible.Content>
2675
+ {#if isItemOpen(item.id)}
2669
2676
  <Card.Content class="p-0 px-4">
2670
2677
  <div class="pt-[14px] pb-[16px]">
2671
2678
  <div class="properties-list flex flex-col" style="gap: 8px;">
@@ -2684,7 +2691,7 @@
2684
2691
 
2685
2692
  {#if isVisible && InputComponent}
2686
2693
  {@const isFontIc = (property.inputController?.type || '').toLowerCase() === 'font'}
2687
- <div class="ictrl input-controller flex {isFontIc ? 'flex-col items-stretch' : 'items-center justify-between'} w-full p-0 browser-input-wrapper"
2694
+ <div class="ictrl input-controller flex {isFontIc ? 'font-ic-host flex-col items-stretch' : 'items-center justify-between'} w-full p-0 browser-input-wrapper"
2688
2695
  class:double-height={isFontIc}
2689
2696
  >
2690
2697
  {#if !isFontIc && InputComponent !== BrowserInputController}
@@ -2745,6 +2752,7 @@
2745
2752
  </div>
2746
2753
  </div>
2747
2754
  </Card.Content>
2755
+ {/if}
2748
2756
  </Collapsible.Content>
2749
2757
  </Collapsible.Root>
2750
2758
  </Card.Root>
@@ -3338,6 +3346,23 @@
3338
3346
  flex-shrink: 0 !important;
3339
3347
  }
3340
3348
 
3349
+ /* FontIC is two stacked 185px rows with its own labels. Do not squeeze
3350
+ the whole controller into the single 185px color column (that hid labels). */
3351
+ :global(.input-controller.font-ic-host) {
3352
+ display: flex !important;
3353
+ flex-direction: column !important;
3354
+ align-items: stretch !important;
3355
+ justify-content: flex-start !important;
3356
+ }
3357
+
3358
+ :global(.input-controller.font-ic-host > div:first-child),
3359
+ :global(.input-controller.font-ic-host > div:last-child) {
3360
+ width: 100% !important;
3361
+ max-width: 100% !important;
3362
+ flex: none !important;
3363
+ margin-right: 0 !important;
3364
+ }
3365
+
3341
3366
  /* New animation system */
3342
3367
  :global(.accordion-content) {
3343
3368
  overflow: hidden;