@customviews-js/customviews 1.4.0 → 1.4.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-views.core.cjs.js +293 -105
- package/dist/custom-views.core.cjs.js.map +1 -1
- package/dist/custom-views.core.esm.js +293 -105
- package/dist/custom-views.core.esm.js.map +1 -1
- package/dist/custom-views.esm.js +293 -105
- package/dist/custom-views.esm.js.map +1 -1
- package/dist/custom-views.js +293 -105
- package/dist/custom-views.js.map +1 -1
- package/dist/custom-views.min.js +2 -2
- package/dist/custom-views.min.js.map +1 -1
- package/dist/types/core/core.d.ts +6 -4
- package/dist/types/core/core.d.ts.map +1 -1
- package/dist/types/core/toggle-manager.d.ts +12 -2
- package/dist/types/core/toggle-manager.d.ts.map +1 -1
- package/dist/types/core/url-state-manager.d.ts.map +1 -1
- package/dist/types/core/widget.d.ts.map +1 -1
- package/dist/types/styles/toggle-styles.d.ts +1 -1
- package/dist/types/styles/toggle-styles.d.ts.map +1 -1
- package/dist/types/styles/widget-styles.d.ts +1 -1
- package/dist/types/styles/widget-styles.d.ts.map +1 -1
- package/dist/types/types/types.d.ts +4 -2
- package/dist/types/types/types.d.ts.map +1 -1
- package/dist/types/utils/icons.d.ts +2 -0
- package/dist/types/utils/icons.d.ts.map +1 -1
- package/package.json +10 -4
package/dist/custom-views.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @customviews-js/customviews v1.4.0
|
|
2
|
+
* @customviews-js/customviews v1.4.1-beta.0
|
|
3
3
|
* (c) 2025 Chan Ger Teck
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -169,8 +169,12 @@
|
|
|
169
169
|
// Create a compact representation
|
|
170
170
|
const compact = {};
|
|
171
171
|
// Add toggles if present and non-empty
|
|
172
|
-
if (state.
|
|
173
|
-
compact.t = state.
|
|
172
|
+
if (state.shownToggles && state.shownToggles.length > 0) {
|
|
173
|
+
compact.t = state.shownToggles;
|
|
174
|
+
}
|
|
175
|
+
// Add peek toggles if present and non-empty
|
|
176
|
+
if (state.peekToggles && state.peekToggles.length > 0) {
|
|
177
|
+
compact.p = state.peekToggles;
|
|
174
178
|
}
|
|
175
179
|
// Add tab groups if present
|
|
176
180
|
if (state.tabs && Object.keys(state.tabs).length > 0) {
|
|
@@ -231,7 +235,8 @@
|
|
|
231
235
|
// Reconstruct State from compact format
|
|
232
236
|
// Reconstruct Toggles
|
|
233
237
|
const state = {
|
|
234
|
-
|
|
238
|
+
shownToggles: Array.isArray(compact.t) ? compact.t : [],
|
|
239
|
+
peekToggles: Array.isArray(compact.p) ? compact.p : []
|
|
235
240
|
};
|
|
236
241
|
// Reconstruct Tabs
|
|
237
242
|
if (Array.isArray(compact.g)) {
|
|
@@ -444,6 +449,12 @@
|
|
|
444
449
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"/>
|
|
445
450
|
</svg>`;
|
|
446
451
|
}
|
|
452
|
+
function getChevronDownIcon() {
|
|
453
|
+
return `<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>`;
|
|
454
|
+
}
|
|
455
|
+
function getChevronUpIcon() {
|
|
456
|
+
return `<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"></polyline></svg>`;
|
|
457
|
+
}
|
|
447
458
|
|
|
448
459
|
// Constants for selectors
|
|
449
460
|
const TABGROUP_SELECTOR$1 = 'cv-tabgroup';
|
|
@@ -1014,20 +1025,33 @@
|
|
|
1014
1025
|
* ToggleManager handles discovery, visibility, and asset rendering for toggle elements
|
|
1015
1026
|
*/
|
|
1016
1027
|
class ToggleManager {
|
|
1028
|
+
/**
|
|
1029
|
+
* Track locally expanded elements (that were in peek mode but user expanded them)
|
|
1030
|
+
*/
|
|
1031
|
+
static expandedPeekElements = new WeakSet();
|
|
1017
1032
|
/**
|
|
1018
1033
|
* Apply toggle visibility to a given list of toggle elements
|
|
1019
1034
|
*/
|
|
1020
|
-
static
|
|
1021
|
-
|
|
1035
|
+
static applyTogglesVisibility(allToggleElements, activeToggles, peekToggles = []) {
|
|
1036
|
+
allToggleElements.forEach(el => {
|
|
1022
1037
|
const categories = this.getToggleCategories(el);
|
|
1023
1038
|
const shouldShow = categories.some(cat => activeToggles.includes(cat));
|
|
1024
|
-
|
|
1039
|
+
const shouldPeek = !shouldShow && categories.some(cat => peekToggles.includes(cat));
|
|
1040
|
+
if (!shouldPeek) {
|
|
1041
|
+
this.expandedPeekElements.delete(el);
|
|
1042
|
+
}
|
|
1043
|
+
// If locally expanded, treat as shown (override peek)
|
|
1044
|
+
// Note: If neither show nor peek is active (i.e. hidden), local expansion is ignored/cleared effectively
|
|
1045
|
+
this.applyToggleVisibility(el, shouldShow || (shouldPeek && this.expandedPeekElements.has(el)), shouldPeek && !this.expandedPeekElements.has(el));
|
|
1025
1046
|
});
|
|
1026
1047
|
}
|
|
1027
1048
|
/**
|
|
1028
1049
|
* Render assets into a given list of toggle elements that are currently visible
|
|
1050
|
+
* Toggles that have a toggleId and are currently visible will have their assets rendered (if any)
|
|
1029
1051
|
*/
|
|
1030
|
-
static
|
|
1052
|
+
static renderToggleAssets(elements, activeToggles, assetsManager) {
|
|
1053
|
+
// TO DO: (gerteck) Enable for peek toggles as well
|
|
1054
|
+
// Also, rework the rendering logic again to make it more user friendly.
|
|
1031
1055
|
elements.forEach(el => {
|
|
1032
1056
|
const categories = this.getToggleCategories(el);
|
|
1033
1057
|
const toggleId = this.getToggleId(el);
|
|
@@ -1040,6 +1064,7 @@
|
|
|
1040
1064
|
}
|
|
1041
1065
|
/**
|
|
1042
1066
|
* Get toggle categories from an element (supports both data attributes and cv-toggle elements)
|
|
1067
|
+
* Note: a toggle can have multiple categories.
|
|
1043
1068
|
*/
|
|
1044
1069
|
static getToggleCategories(el) {
|
|
1045
1070
|
if (el.tagName.toLowerCase() === 'cv-toggle') {
|
|
@@ -1060,14 +1085,101 @@
|
|
|
1060
1085
|
/**
|
|
1061
1086
|
* Apply simple class-based visibility to a toggle element
|
|
1062
1087
|
*/
|
|
1063
|
-
static applyToggleVisibility(
|
|
1088
|
+
static applyToggleVisibility(toggleElement, visible, peek = false) {
|
|
1089
|
+
const isLocallyExpanded = this.expandedPeekElements.has(toggleElement);
|
|
1064
1090
|
if (visible) {
|
|
1065
|
-
|
|
1066
|
-
|
|
1091
|
+
toggleElement.classList.remove('cv-hidden', 'cv-peek');
|
|
1092
|
+
toggleElement.classList.add('cv-visible');
|
|
1093
|
+
// Show collapse button ONLY if locally expanded (meaning we are actually in peek mode but expanded).
|
|
1094
|
+
// If globally visible (because of 'Show' state), isLocallyExpanded should have been cleared by applyTogglesVisibility,
|
|
1095
|
+
// so this will be false, and button will be removed.
|
|
1096
|
+
this.manageExpandButton(toggleElement, false, isLocallyExpanded);
|
|
1097
|
+
}
|
|
1098
|
+
else if (peek) {
|
|
1099
|
+
toggleElement.classList.remove('cv-hidden', 'cv-visible');
|
|
1100
|
+
toggleElement.classList.add('cv-peek');
|
|
1101
|
+
// Show/create expand button if peeked
|
|
1102
|
+
this.manageExpandButton(toggleElement, true, false);
|
|
1067
1103
|
}
|
|
1068
1104
|
else {
|
|
1069
|
-
|
|
1070
|
-
|
|
1105
|
+
toggleElement.classList.add('cv-hidden');
|
|
1106
|
+
toggleElement.classList.remove('cv-visible', 'cv-peek');
|
|
1107
|
+
// Ensure button is gone/hidden
|
|
1108
|
+
this.manageExpandButton(toggleElement, false, false);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Manage the presence of the inline Expand/Collapse button using a wrapper approach
|
|
1113
|
+
*/
|
|
1114
|
+
static manageExpandButton(toggleElement, showExpand, showCollapse = false) {
|
|
1115
|
+
// 1. Ensure wrapper exists
|
|
1116
|
+
let wrapper = toggleElement.parentElement;
|
|
1117
|
+
if (!wrapper || !wrapper.classList.contains('cv-wrapper')) {
|
|
1118
|
+
wrapper = document.createElement('div');
|
|
1119
|
+
wrapper.className = 'cv-wrapper';
|
|
1120
|
+
toggleElement.parentNode?.insertBefore(wrapper, toggleElement);
|
|
1121
|
+
wrapper.appendChild(toggleElement);
|
|
1122
|
+
}
|
|
1123
|
+
const btn = wrapper.querySelector('.cv-expand-btn');
|
|
1124
|
+
// 2. Handle "No Button" case (neither expand nor collapse)
|
|
1125
|
+
if (!showExpand && !showCollapse) {
|
|
1126
|
+
if (btn)
|
|
1127
|
+
btn.style.display = 'none';
|
|
1128
|
+
// If content is visible globally (not hidden), ensure wrapper has 'cv-expanded'
|
|
1129
|
+
// to hide the peek fade effect (since fade is for peek state only).
|
|
1130
|
+
if (!toggleElement.classList.contains('cv-hidden')) {
|
|
1131
|
+
wrapper.classList.add('cv-expanded');
|
|
1132
|
+
}
|
|
1133
|
+
else {
|
|
1134
|
+
wrapper.classList.remove('cv-expanded');
|
|
1135
|
+
}
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
// 3. Handle Button Needed (Expand or Collapse)
|
|
1139
|
+
const action = showExpand ? 'expand' : 'collapse';
|
|
1140
|
+
// Update Wrapper Class Logic
|
|
1141
|
+
// If showExpand (Peek state) -> remove cv-expanded (show fade)
|
|
1142
|
+
// If showCollapse (Expanded peek) -> add cv-expanded (hide fade)
|
|
1143
|
+
if (showExpand) {
|
|
1144
|
+
wrapper.classList.remove('cv-expanded');
|
|
1145
|
+
}
|
|
1146
|
+
else {
|
|
1147
|
+
if (!wrapper.classList.contains('cv-expanded'))
|
|
1148
|
+
wrapper.classList.add('cv-expanded');
|
|
1149
|
+
}
|
|
1150
|
+
// Check if existing button matches desired state
|
|
1151
|
+
const currentAction = btn?.getAttribute('data-action');
|
|
1152
|
+
if (btn && currentAction === action) {
|
|
1153
|
+
btn.style.display = 'flex';
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
// 4. Create New Button (if missing or state changed)
|
|
1157
|
+
const iconSvg = showExpand ? getChevronDownIcon() : getChevronUpIcon();
|
|
1158
|
+
const newBtn = document.createElement('button');
|
|
1159
|
+
newBtn.className = 'cv-expand-btn';
|
|
1160
|
+
newBtn.innerHTML = iconSvg;
|
|
1161
|
+
newBtn.setAttribute('aria-label', showExpand ? 'Expand content' : 'Collapse content');
|
|
1162
|
+
newBtn.setAttribute('data-action', action); // Track state
|
|
1163
|
+
newBtn.style.display = 'flex';
|
|
1164
|
+
newBtn.addEventListener('click', (e) => {
|
|
1165
|
+
e.stopPropagation();
|
|
1166
|
+
// Logic: Toggle expansion state
|
|
1167
|
+
if (showExpand) {
|
|
1168
|
+
wrapper.classList.add('cv-expanded');
|
|
1169
|
+
this.expandedPeekElements.add(toggleElement);
|
|
1170
|
+
this.applyToggleVisibility(toggleElement, true, false);
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
wrapper.classList.remove('cv-expanded');
|
|
1174
|
+
this.expandedPeekElements.delete(toggleElement);
|
|
1175
|
+
this.applyToggleVisibility(toggleElement, false, true);
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
if (btn) {
|
|
1179
|
+
btn.replaceWith(newBtn);
|
|
1180
|
+
}
|
|
1181
|
+
else {
|
|
1182
|
+
wrapper.appendChild(newBtn);
|
|
1071
1183
|
}
|
|
1072
1184
|
}
|
|
1073
1185
|
/**
|
|
@@ -1075,15 +1187,15 @@
|
|
|
1075
1187
|
* This includes applying visibility and rendering assets.
|
|
1076
1188
|
*/
|
|
1077
1189
|
static initializeToggles(root, activeToggles, assetsManager) {
|
|
1078
|
-
const
|
|
1190
|
+
const allToggleElements = [];
|
|
1079
1191
|
if (root.matches('[data-cv-toggle], [data-customviews-toggle], cv-toggle')) {
|
|
1080
|
-
|
|
1192
|
+
allToggleElements.push(root);
|
|
1081
1193
|
}
|
|
1082
|
-
root.querySelectorAll('[data-cv-toggle], [data-customviews-toggle], cv-toggle').forEach(el =>
|
|
1083
|
-
if (
|
|
1194
|
+
root.querySelectorAll('[data-cv-toggle], [data-customviews-toggle], cv-toggle').forEach(el => allToggleElements.push(el));
|
|
1195
|
+
if (allToggleElements.length === 0)
|
|
1084
1196
|
return;
|
|
1085
|
-
this.
|
|
1086
|
-
this.
|
|
1197
|
+
this.applyTogglesVisibility(allToggleElements, activeToggles);
|
|
1198
|
+
this.renderToggleAssets(allToggleElements, activeToggles, assetsManager);
|
|
1087
1199
|
}
|
|
1088
1200
|
}
|
|
1089
1201
|
|
|
@@ -1191,17 +1303,16 @@
|
|
|
1191
1303
|
const TOGGLE_STYLES = `
|
|
1192
1304
|
/* Core toggle visibility transitions */
|
|
1193
1305
|
[data-cv-toggle], [data-customviews-toggle], cv-toggle {
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
margin 150ms ease;
|
|
1198
|
-
will-change: opacity, transform, max-height, margin;
|
|
1306
|
+
display: block;
|
|
1307
|
+
overflow: hidden;
|
|
1308
|
+
/* Removed transitions for instant toggling */
|
|
1199
1309
|
}
|
|
1200
1310
|
|
|
1311
|
+
/* Open State */
|
|
1201
1312
|
.cv-visible {
|
|
1202
1313
|
opacity: 1 !important;
|
|
1203
1314
|
transform: translateY(0) !important;
|
|
1204
|
-
max-height:
|
|
1315
|
+
max-height: none !important;
|
|
1205
1316
|
}
|
|
1206
1317
|
|
|
1207
1318
|
.cv-hidden {
|
|
@@ -1217,6 +1328,61 @@
|
|
|
1217
1328
|
margin-bottom: 0 !important;
|
|
1218
1329
|
overflow: hidden !important;
|
|
1219
1330
|
}
|
|
1331
|
+
|
|
1332
|
+
/* Close/Peek State */
|
|
1333
|
+
.cv-peek {
|
|
1334
|
+
display: block !important;
|
|
1335
|
+
max-height: 70px !important;
|
|
1336
|
+
overflow: hidden !important;
|
|
1337
|
+
opacity: 1 !important;
|
|
1338
|
+
transform: translateY(0) !important;
|
|
1339
|
+
mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
|
|
1340
|
+
-webkit-mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
.cv-wrapper {
|
|
1344
|
+
position: relative;
|
|
1345
|
+
width: 100%;
|
|
1346
|
+
display: block;
|
|
1347
|
+
margin-bottom: 24px; /* Space for the button */
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
.cv-expand-btn {
|
|
1351
|
+
position: absolute;
|
|
1352
|
+
bottom: -28px; /* Mostly outside, slight overlap */
|
|
1353
|
+
left: 50%;
|
|
1354
|
+
transform: translateX(-50%);
|
|
1355
|
+
display: flex;
|
|
1356
|
+
background: transparent;
|
|
1357
|
+
border: none;
|
|
1358
|
+
border-radius: 50%;
|
|
1359
|
+
padding: 4px;
|
|
1360
|
+
width: 32px;
|
|
1361
|
+
height: 32px;
|
|
1362
|
+
cursor: pointer;
|
|
1363
|
+
z-index: 100;
|
|
1364
|
+
align-items: center;
|
|
1365
|
+
justify-content: center;
|
|
1366
|
+
color: #888;
|
|
1367
|
+
transition: all 0.2s ease;
|
|
1368
|
+
box-shadow: none;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
.cv-expand-btn:hover {
|
|
1372
|
+
background: rgba(0, 0, 0, 0.05);
|
|
1373
|
+
color: #000;
|
|
1374
|
+
transform: translateX(-50%) scale(1.1);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
.cv-expand-btn svg {
|
|
1378
|
+
display: block;
|
|
1379
|
+
opacity: 0.6;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
.cv-expand-btn:hover svg {
|
|
1383
|
+
opacity: 1;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1220
1386
|
`;
|
|
1221
1387
|
|
|
1222
1388
|
/**
|
|
@@ -2606,7 +2772,7 @@ ${TAB_STYLES}
|
|
|
2606
2772
|
});
|
|
2607
2773
|
}
|
|
2608
2774
|
const computedState = {
|
|
2609
|
-
|
|
2775
|
+
shownToggles: this.config.toggles?.map(t => t.id) || [],
|
|
2610
2776
|
tabs
|
|
2611
2777
|
};
|
|
2612
2778
|
return computedState;
|
|
@@ -2678,9 +2844,9 @@ ${TAB_STYLES}
|
|
|
2678
2844
|
const initialTop = anchorElement.getBoundingClientRect().top;
|
|
2679
2845
|
const currentTabs = this.getCurrentActiveTabs();
|
|
2680
2846
|
currentTabs[groupId] = tabId;
|
|
2681
|
-
const
|
|
2847
|
+
const currentState = this.getCurrentState();
|
|
2682
2848
|
const newState = {
|
|
2683
|
-
|
|
2849
|
+
...currentState,
|
|
2684
2850
|
tabs: currentTabs,
|
|
2685
2851
|
};
|
|
2686
2852
|
// 2. Apply state with scroll anchor information
|
|
@@ -2736,7 +2902,8 @@ ${TAB_STYLES}
|
|
|
2736
2902
|
// 1. URL State
|
|
2737
2903
|
const urlState = URLStateManager.parseURL();
|
|
2738
2904
|
if (urlState) {
|
|
2739
|
-
|
|
2905
|
+
// Apply URL state temporarily (do not persist until interaction)
|
|
2906
|
+
this.applyState(urlState, { persist: false });
|
|
2740
2907
|
return;
|
|
2741
2908
|
}
|
|
2742
2909
|
// 2. Persisted State
|
|
@@ -2750,9 +2917,10 @@ ${TAB_STYLES}
|
|
|
2750
2917
|
}
|
|
2751
2918
|
/**
|
|
2752
2919
|
* Apply a custom state, saves to localStorage and updates the URL
|
|
2753
|
-
*
|
|
2920
|
+
* 'source' in options indicates the origin of the state change
|
|
2754
2921
|
* (e.g., 'widget' to trigger scroll behavior)
|
|
2755
|
-
*
|
|
2922
|
+
* 'scrollAnchor' in options indicates the element to maintain scroll position of
|
|
2923
|
+
* 'persist' (default true) to control whether to save to localStorage
|
|
2756
2924
|
*/
|
|
2757
2925
|
applyState(state, options) {
|
|
2758
2926
|
// console.log(`[Core] applyState called with source: ${options?.source}`, state);
|
|
@@ -2762,7 +2930,10 @@ ${TAB_STYLES}
|
|
|
2762
2930
|
}
|
|
2763
2931
|
const snapshot = this.cloneState(state);
|
|
2764
2932
|
this.renderState(snapshot);
|
|
2765
|
-
|
|
2933
|
+
// Only persist if explicitly requested (default true)
|
|
2934
|
+
if (options?.persist !== false) {
|
|
2935
|
+
this.persistenceManager.persistState(snapshot);
|
|
2936
|
+
}
|
|
2766
2937
|
if (this.showUrlEnabled) {
|
|
2767
2938
|
URLStateManager.updateURL(snapshot);
|
|
2768
2939
|
}
|
|
@@ -2789,14 +2960,13 @@ ${TAB_STYLES}
|
|
|
2789
2960
|
renderState(state) {
|
|
2790
2961
|
this.observer?.disconnect();
|
|
2791
2962
|
this.lastAppliedState = this.cloneState(state);
|
|
2792
|
-
const toggles = state?.
|
|
2963
|
+
const toggles = state?.shownToggles || [];
|
|
2793
2964
|
const finalToggles = this.visibilityManager.filterVisibleToggles(toggles);
|
|
2794
|
-
const
|
|
2965
|
+
const allToggleElements = Array.from(this.componentRegistry.toggles);
|
|
2795
2966
|
const tabGroupElements = Array.from(this.componentRegistry.tabGroups);
|
|
2796
|
-
|
|
2797
|
-
ToggleManager.applyToggles(toggleElements, finalToggles);
|
|
2967
|
+
ToggleManager.applyTogglesVisibility(allToggleElements, finalToggles, state.peekToggles);
|
|
2798
2968
|
// Render assets into toggles
|
|
2799
|
-
ToggleManager.
|
|
2969
|
+
ToggleManager.renderToggleAssets(allToggleElements, finalToggles, this.assetsManager);
|
|
2800
2970
|
// Apply tab selections
|
|
2801
2971
|
TabManager.applyTabSelections(tabGroupElements, state.tabs || {}, this.config.tabGroups);
|
|
2802
2972
|
// Update nav active states (without rebuilding)
|
|
@@ -2827,16 +2997,16 @@ ${TAB_STYLES}
|
|
|
2827
2997
|
URLStateManager.clearURL();
|
|
2828
2998
|
}
|
|
2829
2999
|
/**
|
|
2830
|
-
* Get the
|
|
3000
|
+
* Get the full current state including active toggles, peek toggles, and tabs
|
|
2831
3001
|
*/
|
|
2832
|
-
|
|
3002
|
+
getCurrentState() {
|
|
2833
3003
|
if (this.lastAppliedState) {
|
|
2834
|
-
return this.lastAppliedState
|
|
3004
|
+
return this.cloneState(this.lastAppliedState);
|
|
2835
3005
|
}
|
|
2836
3006
|
if (this.config) {
|
|
2837
|
-
return this.getComputedDefaultState()
|
|
3007
|
+
return this.cloneState(this.getComputedDefaultState());
|
|
2838
3008
|
}
|
|
2839
|
-
return
|
|
3009
|
+
return {};
|
|
2840
3010
|
}
|
|
2841
3011
|
/**
|
|
2842
3012
|
* Clear all persistence and reset to default
|
|
@@ -3532,10 +3702,6 @@ ${TAB_STYLES}
|
|
|
3532
3702
|
color: rgba(255, 255, 255, 0.6);
|
|
3533
3703
|
}
|
|
3534
3704
|
|
|
3535
|
-
.cv-widget-theme-dark .cv-toggle-slider {
|
|
3536
|
-
background: rgba(255, 255, 255, 0.2);
|
|
3537
|
-
}
|
|
3538
|
-
|
|
3539
3705
|
.cv-widget-theme-dark .cv-tab-group-description {
|
|
3540
3706
|
color: rgba(255, 255, 255, 0.8);
|
|
3541
3707
|
}
|
|
@@ -3656,40 +3822,32 @@ ${TAB_STYLES}
|
|
|
3656
3822
|
}
|
|
3657
3823
|
|
|
3658
3824
|
.cv-toggle-input {
|
|
3825
|
+
/* Only hide if it is part of a custom slider toggle */
|
|
3826
|
+
}
|
|
3827
|
+
.cv-toggle-label .cv-toggle-input {
|
|
3659
3828
|
opacity: 0;
|
|
3660
3829
|
width: 0;
|
|
3661
3830
|
height: 0;
|
|
3662
3831
|
}
|
|
3663
3832
|
|
|
3664
|
-
.cv-toggle-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
left: 0;
|
|
3668
|
-
right: 0;
|
|
3669
|
-
bottom: 0;
|
|
3670
|
-
background: rgba(0, 0, 0, 0.2);
|
|
3671
|
-
border-radius: 9999px;
|
|
3672
|
-
transition: background-color 0.2s ease;
|
|
3673
|
-
}
|
|
3674
|
-
|
|
3675
|
-
.cv-toggle-slider:before {
|
|
3676
|
-
position: absolute;
|
|
3677
|
-
content: "";
|
|
3678
|
-
height: 1rem;
|
|
3679
|
-
width: 1rem;
|
|
3680
|
-
left: 0.25rem;
|
|
3681
|
-
bottom: 0.25rem;
|
|
3682
|
-
background: white;
|
|
3683
|
-
border-radius: 50%;
|
|
3684
|
-
transition: transform 0.2s ease;
|
|
3833
|
+
.cv-toggle-radios {
|
|
3834
|
+
display: flex;
|
|
3835
|
+
gap: 8px;
|
|
3685
3836
|
}
|
|
3686
3837
|
|
|
3687
|
-
.cv-
|
|
3688
|
-
|
|
3838
|
+
.cv-radio-label {
|
|
3839
|
+
display: flex;
|
|
3840
|
+
align-items: center;
|
|
3841
|
+
gap: 4px;
|
|
3842
|
+
font-size: 0.85rem;
|
|
3843
|
+
cursor: pointer;
|
|
3689
3844
|
}
|
|
3690
3845
|
|
|
3691
|
-
.cv-
|
|
3692
|
-
|
|
3846
|
+
.cv-radio-label input {
|
|
3847
|
+
margin: 0;
|
|
3848
|
+
opacity: 1;
|
|
3849
|
+
width: auto;
|
|
3850
|
+
height: auto;
|
|
3693
3851
|
}
|
|
3694
3852
|
|
|
3695
3853
|
/* Dark theme toggle switch styles */
|
|
@@ -4506,10 +4664,20 @@ ${TAB_STYLES}
|
|
|
4506
4664
|
<div>
|
|
4507
4665
|
<p class="cv-toggle-title">${toggle.label || toggle.id}</p>
|
|
4508
4666
|
</div>
|
|
4509
|
-
<
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4667
|
+
<div class="cv-toggle-radios">
|
|
4668
|
+
<label class="cv-radio-label" title="Hide">
|
|
4669
|
+
<input class="cv-toggle-input" type="radio" name="cv-toggle-${toggle.id}" value="hide" data-toggle="${toggle.id}"/>
|
|
4670
|
+
<span>Hide</span>
|
|
4671
|
+
</label>
|
|
4672
|
+
<label class="cv-radio-label" title="Peek">
|
|
4673
|
+
<input class="cv-toggle-input" type="radio" name="cv-toggle-${toggle.id}" value="peek" data-toggle="${toggle.id}"/>
|
|
4674
|
+
<span>Peek</span>
|
|
4675
|
+
</label>
|
|
4676
|
+
<label class="cv-radio-label" title="Show">
|
|
4677
|
+
<input class="cv-toggle-input" type="radio" name="cv-toggle-${toggle.id}" value="show" data-toggle="${toggle.id}"/>
|
|
4678
|
+
<span>Show</span>
|
|
4679
|
+
</label>
|
|
4680
|
+
</div>
|
|
4513
4681
|
</div>
|
|
4514
4682
|
</div>
|
|
4515
4683
|
`).join('');
|
|
@@ -4710,10 +4878,11 @@ ${TAB_STYLES}
|
|
|
4710
4878
|
if (groupId && tabId) {
|
|
4711
4879
|
const currentTabs = this.core.getCurrentActiveTabs();
|
|
4712
4880
|
currentTabs[groupId] = tabId;
|
|
4713
|
-
const
|
|
4881
|
+
const currentState = this.core.getCurrentState();
|
|
4714
4882
|
const newState = {
|
|
4715
|
-
|
|
4716
|
-
|
|
4883
|
+
shownToggles: currentState.shownToggles || [],
|
|
4884
|
+
peekToggles: currentState.peekToggles || [], // Preserve peek state, fallback to empty array
|
|
4885
|
+
tabs: currentTabs,
|
|
4717
4886
|
};
|
|
4718
4887
|
this.core.applyState(newState, { source: 'widget' });
|
|
4719
4888
|
}
|
|
@@ -4811,25 +4980,33 @@ ${TAB_STYLES}
|
|
|
4811
4980
|
}
|
|
4812
4981
|
// Collect toggle values
|
|
4813
4982
|
const toggles = [];
|
|
4814
|
-
const
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
tabs[groupId] = select.value;
|
|
4983
|
+
const peekToggles = [];
|
|
4984
|
+
// Get all radio inputs
|
|
4985
|
+
const radios = this.stateModal.querySelectorAll('input[type="radio"]:checked');
|
|
4986
|
+
radios.forEach(radio => {
|
|
4987
|
+
const input = radio;
|
|
4988
|
+
const toggleId = input.getAttribute('data-toggle');
|
|
4989
|
+
if (toggleId) {
|
|
4990
|
+
if (input.value === 'show') {
|
|
4991
|
+
toggles.push(toggleId);
|
|
4992
|
+
}
|
|
4993
|
+
else if (input.value === 'peek') {
|
|
4994
|
+
peekToggles.push(toggleId);
|
|
4995
|
+
}
|
|
4828
4996
|
}
|
|
4829
4997
|
});
|
|
4830
|
-
const result = { toggles };
|
|
4831
|
-
|
|
4832
|
-
|
|
4998
|
+
const result = { shownToggles: toggles, peekToggles };
|
|
4999
|
+
// Get active tabs from selects
|
|
5000
|
+
const selects = this.stateModal.querySelectorAll('select[data-group-id]');
|
|
5001
|
+
if (selects.length > 0) {
|
|
5002
|
+
result.tabs = {};
|
|
5003
|
+
selects.forEach(select => {
|
|
5004
|
+
const el = select;
|
|
5005
|
+
const groupId = el.getAttribute('data-group-id');
|
|
5006
|
+
if (groupId) {
|
|
5007
|
+
result.tabs[groupId] = el.value;
|
|
5008
|
+
}
|
|
5009
|
+
});
|
|
4833
5010
|
}
|
|
4834
5011
|
return result;
|
|
4835
5012
|
}
|
|
@@ -4849,18 +5026,29 @@ ${TAB_STYLES}
|
|
|
4849
5026
|
loadCurrentStateIntoForm() {
|
|
4850
5027
|
if (!this.stateModal)
|
|
4851
5028
|
return;
|
|
4852
|
-
//
|
|
4853
|
-
const
|
|
4854
|
-
|
|
5029
|
+
// We need complete state for both shown and peek toggles
|
|
5030
|
+
const currentState = this.core.getCurrentState();
|
|
5031
|
+
const currentToggles = currentState.shownToggles || [];
|
|
5032
|
+
const currentPeekToggles = currentState.peekToggles || [];
|
|
5033
|
+
// Reset all inputs first (optional, but good for clarity)
|
|
4855
5034
|
const allToggleInputs = this.stateModal.querySelectorAll('.cv-toggle-input');
|
|
4856
|
-
|
|
4857
|
-
|
|
5035
|
+
// Identify unique toggles present in the modal
|
|
5036
|
+
const uniqueToggles = new Set();
|
|
5037
|
+
allToggleInputs.forEach(input => {
|
|
5038
|
+
if (input.dataset.toggle)
|
|
5039
|
+
uniqueToggles.add(input.dataset.toggle);
|
|
4858
5040
|
});
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
5041
|
+
uniqueToggles.forEach(toggleId => {
|
|
5042
|
+
let valueToSelect = 'hide';
|
|
5043
|
+
if (currentToggles.includes(toggleId)) {
|
|
5044
|
+
valueToSelect = 'show';
|
|
5045
|
+
}
|
|
5046
|
+
else if (currentPeekToggles.includes(toggleId)) {
|
|
5047
|
+
valueToSelect = 'peek';
|
|
5048
|
+
}
|
|
5049
|
+
const input = this.stateModal.querySelector(`input[name="cv-toggle-${toggleId}"][value="${valueToSelect}"]`);
|
|
5050
|
+
if (input) {
|
|
5051
|
+
input.checked = true;
|
|
4864
5052
|
}
|
|
4865
5053
|
});
|
|
4866
5054
|
// Load tab group selections
|