vgapp 1.3.9 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,48 +1,48 @@
1
1
  export function normalizeNonNegativeInt(value, fallback = 0) {
2
- const parsed = Number.parseInt(value, 10);
3
- return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
2
+ const parsed = Number.parseInt(value, 10);
3
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
4
4
  }
5
5
 
6
6
  export function normalizeBooleanOption(value, fallback = false) {
7
- if (value === undefined || value === null) {
8
- return fallback;
9
- }
10
- const normalized = String(value).toLowerCase().trim();
11
- if (normalized === 'true' || normalized === '1') {
12
- return true;
13
- }
14
- if (normalized === 'false' || normalized === '0') {
15
- return false;
16
- }
17
- return Boolean(value);
7
+ if (value === undefined || value === null) {
8
+ return fallback;
9
+ }
10
+ const normalized = String(value).toLowerCase().trim();
11
+ if (normalized === 'true' || normalized === '1') {
12
+ return true;
13
+ }
14
+ if (normalized === 'false' || normalized === '0') {
15
+ return false;
16
+ }
17
+ return Boolean(value);
18
18
  }
19
19
 
20
20
  export function normalizeEnabledFlag(value, fallback = true) {
21
- if (value === undefined || value === null) {
22
- return fallback;
23
- }
24
- const normalized = String(value).toLowerCase().trim();
25
- return normalized !== 'false' && normalized !== '0';
21
+ if (value === undefined || value === null) {
22
+ return fallback;
23
+ }
24
+ const normalized = String(value).toLowerCase().trim();
25
+ return normalized !== 'false' && normalized !== '0';
26
26
  }
27
27
 
28
28
  export function safeQuerySelector(selector, root = document) {
29
- const normalized = String(selector || '').trim();
30
- if (!normalized || !root || typeof root.querySelector !== 'function') {
31
- return null;
32
- }
33
- try {
34
- return root.querySelector(normalized);
35
- } catch (error) {
36
- return null;
37
- }
29
+ const normalized = String(selector || '').trim();
30
+ if (!normalized || !root || typeof root.querySelector !== 'function') {
31
+ return null;
32
+ }
33
+ try {
34
+ return root.querySelector(normalized);
35
+ } catch (error) {
36
+ return null;
37
+ }
38
38
  }
39
39
 
40
40
  export function toQueryParamValue(value) {
41
- if (!Array.isArray(value)) {
42
- return value;
43
- }
44
- return value
45
- .map((item) => String(item || '').trim())
46
- .filter((item) => item !== '')
47
- .join(',');
41
+ if (!Array.isArray(value)) {
42
+ return value;
43
+ }
44
+ return value
45
+ .map((item) => String(item || '').trim())
46
+ .filter((item) => item !== '')
47
+ .join(',');
48
48
  }
@@ -3026,12 +3026,34 @@ class VGDynamicTable extends BaseModule {
3026
3026
  return false;
3027
3027
  }
3028
3028
 
3029
- _isCloneStickyHeaderEnabled() {
3030
- if (this._parent && this._parent.classList.contains('table-sticky')) {
3031
- return true;
3032
- }
3033
- return Boolean(this._element && this._element.classList.contains('table-sticky'));
3034
- }
3029
+ _isCloneStickyHeaderEnabled() {
3030
+ const sticky = this._params.stickyHeader || {};
3031
+ const cloneAttr = this._element.getAttribute('data-sticky-header-clone');
3032
+ if (cloneAttr !== null) {
3033
+ const normalized = String(cloneAttr).toLowerCase().trim();
3034
+ return normalized !== 'false' && normalized !== '0';
3035
+ }
3036
+
3037
+ if (sticky.clone !== undefined && sticky.clone !== null) {
3038
+ const normalized = String(sticky.clone).toLowerCase().trim();
3039
+ if (normalized === 'true' || normalized === '1') {
3040
+ return true;
3041
+ }
3042
+ if (normalized === 'false' || normalized === '0') {
3043
+ return false;
3044
+ }
3045
+ return Boolean(sticky.clone);
3046
+ }
3047
+
3048
+ if (this._parent && this._parent.classList.contains('table-sticky')) {
3049
+ return true;
3050
+ }
3051
+ if (this._element && this._element.classList.contains('table-sticky')) {
3052
+ return true;
3053
+ }
3054
+
3055
+ return this._isStickyHeaderEnabled();
3056
+ }
3035
3057
 
3036
3058
  _refreshStickyAndFixedLayout(options = {}) {
3037
3059
  const immediate = Boolean(options && options.immediate);
@@ -3137,12 +3159,13 @@ class VGDynamicTable extends BaseModule {
3137
3159
  };
3138
3160
  }
3139
3161
 
3140
- _getCloneStickyHeaderOffsets() {
3141
- return {
3142
- top: this._readCssSizeVar('--vgdt-sticky-top', 0),
3143
- maxHeight: this._readCssSizeVar('--vgdt-sticky-max-height', 0),
3144
- };
3145
- }
3162
+ _getCloneStickyHeaderOffsets() {
3163
+ const configured = this._getStickyHeaderOffsets();
3164
+ return {
3165
+ top: configured.top || this._readCssSizeVar('--vgdt-sticky-top', 0),
3166
+ maxHeight: configured.maxHeight || this._readCssSizeVar('--vgdt-sticky-max-height', 0),
3167
+ };
3168
+ }
3146
3169
 
3147
3170
  _readCssSizeVar(name, fallback = 0) {
3148
3171
  const sources = [this._parent, this._element, this._tableViewport].filter(Boolean);
@@ -3235,12 +3258,13 @@ class VGDynamicTable extends BaseModule {
3235
3258
  }
3236
3259
  if (state && state.headerWrap && state.headerWrap.parentElement) {
3237
3260
  state.headerWrap.parentElement.removeChild(state.headerWrap);
3238
- }
3239
- this._cloneStickyState = null;
3240
- this._parent.style.removeProperty('--vgdt-sticky-clone-height');
3241
- if (scrollTarget && !this._isStickyHeaderEnabled()) {
3242
- scrollTarget.classList.remove('table-sticky-scroll');
3243
- scrollTarget.style.removeProperty('--vgdt-sticky-max-height');
3261
+ }
3262
+ this._cloneStickyState = null;
3263
+ this._parent.style.removeProperty('--vgdt-sticky-clone-height');
3264
+ this._parent.style.removeProperty('--vgdt-sticky-top');
3265
+ if (scrollTarget && !this._isStickyHeaderEnabled()) {
3266
+ scrollTarget.classList.remove('table-sticky-scroll');
3267
+ scrollTarget.style.removeProperty('--vgdt-sticky-max-height');
3244
3268
  }
3245
3269
  this._updateLayoutResizeBinding();
3246
3270
  return;
@@ -3252,10 +3276,11 @@ class VGDynamicTable extends BaseModule {
3252
3276
 
3253
3277
  const offsets = this._getCloneStickyHeaderOffsets();
3254
3278
 
3255
- if (scrollTarget) {
3256
- if (offsets.maxHeight > 0) {
3257
- scrollTarget.classList.add('table-sticky-scroll');
3258
- scrollTarget.style.setProperty('--vgdt-sticky-max-height', `${offsets.maxHeight}px`);
3279
+ if (scrollTarget) {
3280
+ this._parent.style.setProperty('--vgdt-sticky-top', `${offsets.top}px`);
3281
+ if (offsets.maxHeight > 0) {
3282
+ scrollTarget.classList.add('table-sticky-scroll');
3283
+ scrollTarget.style.setProperty('--vgdt-sticky-max-height', `${offsets.maxHeight}px`);
3259
3284
  } else {
3260
3285
  scrollTarget.classList.remove('table-sticky-scroll');
3261
3286
  scrollTarget.style.removeProperty('--vgdt-sticky-max-height');
@@ -3693,17 +3718,20 @@ class VGDynamicTable extends BaseModule {
3693
3718
  this._refreshStickyAndFixedLayout();
3694
3719
  }
3695
3720
 
3696
- _scrollToPaginationTop() {
3697
- if (!this._isPaginationScrollToTopEnabled()) {
3698
- return;
3699
- }
3700
- if (this._tableViewport) {
3701
- this._tableViewport.scrollTop = 0;
3702
- this._tableViewport.scrollLeft = 0;
3703
- }
3704
- if (typeof window === 'undefined' || !this._parent) {
3705
- return;
3706
- }
3721
+ _scrollToPaginationTop() {
3722
+ if (!this._isPaginationScrollToTopEnabled()) {
3723
+ return;
3724
+ }
3725
+ if (this._tableViewport) {
3726
+ this._tableViewport.scrollTop = 0;
3727
+ this._tableViewport.scrollLeft = 0;
3728
+ }
3729
+ if (this._hasFixedHeightViewport()) {
3730
+ return;
3731
+ }
3732
+ if (typeof window === 'undefined' || !this._parent) {
3733
+ return;
3734
+ }
3707
3735
 
3708
3736
  const targetTop = this._getPaginationScrollTopTarget();
3709
3737
  const currentTop = window.pageYOffset || window.scrollY || 0;
@@ -3720,11 +3748,24 @@ class VGDynamicTable extends BaseModule {
3720
3748
  window.scrollTo({
3721
3749
  top: Math.max(0, Math.round(targetTop)),
3722
3750
  behavior: prefersReducedMotion ? 'auto' : 'smooth',
3723
- });
3724
- }
3725
-
3726
- _getPaginationScrollTopTarget() {
3727
- if (this._isPaginationScrollToWindowTopEnabled()) {
3751
+ });
3752
+ }
3753
+
3754
+ _hasFixedHeightViewport() {
3755
+ if (this._tableViewport && this._tableViewport.classList.contains('table-sticky-scroll')) {
3756
+ return true;
3757
+ }
3758
+
3759
+ const offsets = this._getStickyHeaderOffsets();
3760
+ if (offsets.maxHeight > 0) {
3761
+ return true;
3762
+ }
3763
+
3764
+ return this._readCssSizeVar('--vgdt-sticky-max-height', 0) > 0;
3765
+ }
3766
+
3767
+ _getPaginationScrollTopTarget() {
3768
+ if (this._isPaginationScrollToWindowTopEnabled()) {
3728
3769
  return 0;
3729
3770
  }
3730
3771
  const rect = this._parent.getBoundingClientRect();
@@ -155,12 +155,14 @@
155
155
  &.table-sticky-head {
156
156
  overflow: visible;
157
157
 
158
- .vgdt-table-viewport > table {
159
- thead th {
160
- position: sticky;
161
- top: var(--vgdt-sticky-top, 0px);
162
- z-index: 3;
163
- background: var(--vg-dynamic-table-header-background);
158
+ .vgdt-table-viewport > table {
159
+ overflow: visible;
160
+
161
+ thead th {
162
+ position: sticky;
163
+ top: var(--vgdt-sticky-top, 0px);
164
+ z-index: 3;
165
+ background: var(--vg-dynamic-table-header-background);
164
166
  box-shadow: 0 1px 0 var(--vg-dynamic-table-cell-border-color);
165
167
  }
166
168
 
@@ -258,10 +260,11 @@
258
260
  overflow: auto;
259
261
  }
260
262
 
261
- .vgdt-table-viewport > table {
262
- margin-top: calc(-1 * var(--vgdt-sticky-clone-height, 0px));
263
- }
264
- }
263
+ .vgdt-table-viewport > table {
264
+ overflow: visible;
265
+ margin-top: calc(-1 * var(--vgdt-sticky-clone-height, 0px));
266
+ }
267
+ }
265
268
 
266
269
  }
267
270
 
@@ -0,0 +1,216 @@
1
+ import Selectors from "../../../utils/js/dom/selectors";
2
+ import VGModalDrag from "./vgmodal.drag";
3
+ import VGModalResize from "./vgmodal.resize";
4
+
5
+ const DEFAULTS = {
6
+ drag: {
7
+ enable: false,
8
+ selector: '.vg-modal-content',
9
+ threshold: 4,
10
+ resizeEdgeSize: 8,
11
+ debug: false,
12
+ },
13
+ resize: {
14
+ enable: false,
15
+ edgeSize: 8,
16
+ minWidth: 300,
17
+ minHeight: 160,
18
+ debug: false,
19
+ },
20
+ };
21
+
22
+ class VGModalInteraction {
23
+ constructor(modalElement, dialogElement, contentElement, getParams) {
24
+ this._modalElement = modalElement;
25
+ this._dialogElement = dialogElement;
26
+ this._contentElement = contentElement;
27
+ this._getParams = typeof getParams === 'function' ? getParams : () => ({});
28
+ this._dragHandler = new VGModalDrag(this._modalElement, this._dialogElement);
29
+ this._resizeHandler = new VGModalResize(this._modalElement, this._dialogElement);
30
+ this._config = this._resolveConfig();
31
+
32
+ this._bindHandlers();
33
+ }
34
+
35
+ toggleHandlers() {
36
+ this._config = this._resolveConfig();
37
+ this._bindHandlers();
38
+
39
+ if (this._config.drag.enable) {
40
+ this._dragHandler.enable();
41
+ } else {
42
+ this._dragHandler.disable();
43
+ }
44
+
45
+ if (this._config.resize.enable) {
46
+ this._resizeHandler.enable();
47
+ } else {
48
+ this._resizeHandler.disable();
49
+ }
50
+ }
51
+
52
+ disableHandlers() {
53
+ this._dragHandler.disable();
54
+ this._resizeHandler.disable();
55
+ }
56
+
57
+ syncBounds() {
58
+ if (this._config.resize.enable) {
59
+ this._resizeHandler.syncToViewport();
60
+ }
61
+
62
+ if (this._config.drag.enable) {
63
+ this._dragHandler.syncPosition();
64
+ }
65
+ }
66
+
67
+ saveState() {
68
+ const stateConfig = this._getStateConfig();
69
+ const storageKey = this._getStateStorageKey(stateConfig);
70
+ if (!stateConfig.enable || !storageKey || typeof window === 'undefined' || !window.localStorage) return;
71
+
72
+ try {
73
+ window.localStorage.setItem(storageKey, JSON.stringify(this._captureState()));
74
+ } catch (error) {
75
+ }
76
+ }
77
+
78
+ restoreState() {
79
+ const stateConfig = this._getStateConfig();
80
+ const storageKey = this._getStateStorageKey(stateConfig);
81
+ if (!stateConfig.enable || !storageKey || typeof window === 'undefined' || !window.localStorage) return false;
82
+
83
+ try {
84
+ const rawState = window.localStorage.getItem(storageKey);
85
+ if (!rawState) return false;
86
+
87
+ const parsedState = JSON.parse(rawState);
88
+ this._applyState(parsedState);
89
+ return true;
90
+ } catch (error) {
91
+ return false;
92
+ }
93
+ }
94
+
95
+ dispose() {
96
+ this.disableHandlers();
97
+ }
98
+
99
+ _bindHandlers() {
100
+ this._dragHandler.setOptions(this._config.drag);
101
+ this._resizeHandler.setOptions(this._config.resize);
102
+ }
103
+
104
+ _resolveConfig() {
105
+ const params = this._getParams();
106
+
107
+ return {
108
+ drag: this._normalizeInteractionParams(params.drag, DEFAULTS.drag),
109
+ resize: this._normalizeInteractionParams(params.resize, DEFAULTS.resize),
110
+ };
111
+ }
112
+
113
+ _normalizeInteractionParams(paramsValue, defaults) {
114
+ if (typeof paramsValue === 'boolean') {
115
+ return {...defaults, enable: paramsValue};
116
+ }
117
+
118
+ if (paramsValue && typeof paramsValue === 'object') {
119
+ const hasEnable = Object.prototype.hasOwnProperty.call(paramsValue, 'enable');
120
+ return {
121
+ ...defaults,
122
+ ...paramsValue,
123
+ enable: hasEnable ? Boolean(paramsValue.enable) : true,
124
+ };
125
+ }
126
+
127
+ return {...defaults};
128
+ }
129
+
130
+ _getStateConfig() {
131
+ const params = this._getParams();
132
+ return this._normalizeStateParams(params.state);
133
+ }
134
+
135
+ _normalizeStateParams(paramsValue, defaults = { enable: true, key: '' }) {
136
+ if (typeof paramsValue === 'boolean') {
137
+ return {...defaults, enable: paramsValue};
138
+ }
139
+
140
+ if (paramsValue && typeof paramsValue === 'object') {
141
+ const hasEnable = Object.prototype.hasOwnProperty.call(paramsValue, 'enable');
142
+ const key = typeof paramsValue.key === 'string' ? paramsValue.key.trim() : '';
143
+ return {
144
+ ...defaults,
145
+ ...paramsValue,
146
+ key,
147
+ enable: hasEnable ? Boolean(paramsValue.enable) : true,
148
+ };
149
+ }
150
+
151
+ return {...defaults};
152
+ }
153
+
154
+ _getStateStorageKey(stateConfig = this._getStateConfig()) {
155
+ if (!stateConfig.enable) return '';
156
+
157
+ if (typeof stateConfig.key === 'string' && stateConfig.key.trim()) {
158
+ return stateConfig.key.trim();
159
+ }
160
+
161
+ if (!this._modalElement || !this._modalElement.id) return '';
162
+
163
+ return `vg.modal.state:${window.location.pathname}:${this._modalElement.id}`;
164
+ }
165
+
166
+ _captureState() {
167
+ const dialogStyle = this._dialogElement ? this._dialogElement.style : null;
168
+ const contentElement = this._contentElement || Selectors.find('.vg-modal-content', this._dialogElement);
169
+ const contentStyle = contentElement ? contentElement.style : null;
170
+
171
+ return {
172
+ dialog: dialogStyle ? {
173
+ position: dialogStyle.position,
174
+ margin: dialogStyle.margin,
175
+ left: dialogStyle.left,
176
+ top: dialogStyle.top,
177
+ width: dialogStyle.width,
178
+ height: dialogStyle.height,
179
+ transform: dialogStyle.transform,
180
+ maxWidth: dialogStyle.maxWidth,
181
+ maxHeight: dialogStyle.maxHeight,
182
+ minHeight: dialogStyle.minHeight,
183
+ overflow: dialogStyle.overflow,
184
+ pointerEvents: dialogStyle.pointerEvents,
185
+ transition: dialogStyle.transition,
186
+ willChange: dialogStyle.willChange,
187
+ } : {},
188
+ content: contentStyle ? {
189
+ height: contentStyle.height,
190
+ maxHeight: contentStyle.maxHeight,
191
+ overflow: contentStyle.overflow,
192
+ } : {},
193
+ };
194
+ }
195
+
196
+ _applyState(state) {
197
+ if (!state || typeof state !== 'object') return;
198
+
199
+ const dialogState = state.dialog && typeof state.dialog === 'object' ? state.dialog : {};
200
+ const contentState = state.content && typeof state.content === 'object' ? state.content : {};
201
+ if (this._dialogElement) {
202
+ Object.keys(dialogState).forEach(propertyName => {
203
+ this._dialogElement.style[propertyName] = dialogState[propertyName] || '';
204
+ });
205
+ }
206
+
207
+ const contentElement = this._contentElement || Selectors.find('.vg-modal-content', this._dialogElement);
208
+ if (contentElement) {
209
+ Object.keys(contentState).forEach(propertyName => {
210
+ contentElement.style[propertyName] = contentState[propertyName] || '';
211
+ });
212
+ }
213
+ }
214
+ }
215
+
216
+ export default VGModalInteraction;