inviton-powerduck 0.0.130 → 0.0.133

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.
@@ -62,6 +62,7 @@ class WysiwigEditorComponent extends TsxComponent<WysiwigEditorArgs> implements
62
62
  @Prop() onResized?: (height: number) => void;
63
63
  @Prop({ default: true }) resizable: boolean;
64
64
  skipTrigger: boolean = false;
65
+ resizeObserver: ResizeObserver = null;
65
66
 
66
67
  raiseChangeEvent(value: string) {
67
68
  this.populateValidationDeclaration();
@@ -170,7 +171,7 @@ class WysiwigEditorComponent extends TsxComponent<WysiwigEditorArgs> implements
170
171
 
171
172
  let lastNotifiedHeight = this.initialHeight || null;
172
173
  if (this.onResized != null && this.resizable) {
173
- const resizeObserver = new ResizeObserver((entries) => {
174
+ this.resizeObserver = new ResizeObserver((entries) => {
174
175
  for (const entry of entries) {
175
176
  const height = entry?.contentRect?.height;
176
177
  if (height > 0 && (lastNotifiedHeight == null || Math.abs(height - lastNotifiedHeight) > 2)) { // To keep height stable
@@ -180,7 +181,7 @@ class WysiwigEditorComponent extends TsxComponent<WysiwigEditorArgs> implements
180
181
  }
181
182
  });
182
183
 
183
- resizeObserver.observe(innerEditor[0]);
184
+ this.resizeObserver.observe(innerEditor?.[0]);
184
185
  }
185
186
 
186
187
  innerEditor.on('click', (e) => {
@@ -224,6 +225,13 @@ class WysiwigEditorComponent extends TsxComponent<WysiwigEditorArgs> implements
224
225
 
225
226
  beforeUnmount() {
226
227
  ($(this.$el) as any).trumbowyg('destroy');
228
+
229
+ if (this.resizeObserver != null) {
230
+ const innerEditor = $(this.$el).find('.trumbowyg-box');
231
+ if (innerEditor?.length > 0) {
232
+ this.resizeObserver.unobserve(innerEditor[0]);
233
+ }
234
+ }
227
235
  }
228
236
 
229
237
  buildImageDropdownArr(): string[] {
@@ -59,3 +59,84 @@
59
59
  .modal-dialog.modal-ntl {
60
60
  max-width: 650px;
61
61
  }
62
+
63
+ @media (max-width: 767.99px) {
64
+ .modal-bottom-sheet .modal-dialog {
65
+ position: fixed !important;
66
+ bottom: 0 !important;
67
+ margin: 0 !important;
68
+ width: 100% !important;
69
+ max-width: 100%;
70
+ transition: transform 0.3s ease-out !important;
71
+ }
72
+
73
+ .modal-bottom-sheet .modal-dialog .modal-content {
74
+ border-top-left-radius: 16px;
75
+ border-top-right-radius: 16px;
76
+ padding-top: 0;
77
+ }
78
+
79
+ /* Drag handle */
80
+ .modal-bottom-sheet .drag-handle {
81
+ width: 100%;
82
+ padding-top: 10px;
83
+ padding-bottom: 5px;
84
+ cursor: grab;
85
+ }
86
+
87
+ .modal-bottom-sheet .handle-bar {
88
+ width: 40px;
89
+ height: 4px;
90
+ background-color: #ccc;
91
+ border-radius: 2px;
92
+ margin: 0 auto;
93
+ }
94
+
95
+ .modal.modal-bottom-sheet.fade .modal-dialog {
96
+ transition:
97
+ transform 0.3s ease-out,
98
+ opacity 0.3s ease-out;
99
+ transform: translateY(100%);
100
+ opacity: 0;
101
+ }
102
+
103
+ .modal.modal-bottom-sheet.fade.show .modal-dialog {
104
+ transform: translateY(0);
105
+ opacity: 1;
106
+ }
107
+
108
+ .modal-is-dragging,
109
+ .modal-is-dragging * {
110
+ user-select: none;
111
+ }
112
+
113
+ .modal.modal-bottom-sheet.fade.modal-is-dragging .modal-dialog {
114
+ transition: none !important;
115
+ }
116
+
117
+ .modal.modal-bottom-sheet .modal-body {
118
+ max-height: 80vh;
119
+ overflow: auto;
120
+ }
121
+
122
+ .modal.fade.modal-mobile-fullscreen .modal-dialog {
123
+ margin: 0;
124
+ max-width: 100%;
125
+ border-radius: 0;
126
+ }
127
+
128
+ .modal.fade.modal-mobile-fullscreen .modal-dialog .modal-content,
129
+ .modal.fade.modal-mobile-fullscreen .modal-dialog .modal-header {
130
+ border-radius: 0;
131
+ border-top: 0;
132
+ border-left: 0;
133
+ border-right: 0;
134
+ }
135
+
136
+ .modal.fade.modal-mobile-fullscreen .modal-dialog .modal-footer {
137
+ position: sticky;
138
+ bottom: 0;
139
+ z-index: 1;
140
+ background: inherit;
141
+ }
142
+ }
@@ -18,14 +18,20 @@ interface ModalArgs {
18
18
  icon?: ModalHeaderIcon;
19
19
  blocked?: boolean;
20
20
  cssClass?: string;
21
+ mobileMode?: ModalMobileMode;
21
22
  dismissable?: boolean;
22
23
  backdropStatic?: boolean;
23
- mobileFullscreen?: boolean;
24
24
  modalLazyMode?: boolean;
25
25
  preventHistoryEntry?: boolean;
26
26
  portalTarget?: string;
27
27
  }
28
28
 
29
+ export enum ModalMobileMode {
30
+ Default = 0,
31
+ BottomSheetModal = 1,
32
+ FullScreen = 2,
33
+ }
34
+
29
35
  export enum ModalSize {
30
36
  Normal = 0,
31
37
  Small = 1,
@@ -52,6 +58,7 @@ declare global {
52
58
 
53
59
  export class ModalConfig {
54
60
  static defaultPortalTarget = 'body';
61
+ static defaultMobileMode = ModalMobileMode.BottomSheetModal;
55
62
  }
56
63
 
57
64
  @Component
@@ -63,10 +70,9 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
63
70
  @Prop() cssClass!: string;
64
71
  @Prop() dismissable: boolean;
65
72
  @Prop() backdropStatic!: boolean;
66
- @Prop() mobileFullscreen: boolean;
73
+ @Prop() mobileMode?: ModalMobileMode;
67
74
  @Prop() modalLazyMode: boolean;
68
75
  @Prop() preventHistoryEntry: boolean;
69
- @Prop() alternativePortal: boolean;
70
76
  uuid: string = null;
71
77
  modalShown: boolean = false;
72
78
 
@@ -98,6 +104,129 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
98
104
  }
99
105
  }
100
106
 
107
+ private getModalMobileModeCss(): string {
108
+ if (this.treatMobileAsBottomSheet()) {
109
+ return ' modal-bottom-sheet';
110
+ } else if (this.treatMobileAsFullScreen()) {
111
+ return ' modal-mobile-fullscreen';
112
+ }
113
+
114
+ return '';
115
+ }
116
+
117
+ private handleMobileModeDragBinding() {
118
+ if (!this.treatMobileAsBottomSheet()) {
119
+ return;
120
+ }
121
+
122
+ const modal = this.$refs.modalRoot as HTMLElement;
123
+ if ((modal as any)?._dragBound) {
124
+ return;
125
+ }
126
+
127
+ setTimeout(() => {
128
+ const modal = this.$refs.modalRoot as HTMLElement;
129
+ const modalDialog = modal.querySelector('.modal-dialog') as HTMLElement;
130
+ const dragHandle = modal.querySelector('.drag-handle');
131
+
132
+ let startY = 0;
133
+ let currentY = 0;
134
+ let isDragging = false;
135
+ const threshold = 100;
136
+ const cancelDragging = () => {
137
+ isDragging = false;
138
+ modal.classList.remove('modal-is-dragging');
139
+ };
140
+
141
+ const startDragging = () => {
142
+ isDragging = true;
143
+ modal.classList.add('modal-is-dragging');
144
+ };
145
+
146
+ const onMove = (y) => {
147
+ const translateY = Math.max(y - startY, 0);
148
+ modalDialog.style.transform = `translateY(${translateY}px)`;
149
+ };
150
+
151
+ const endDrag = () => {
152
+ cancelDragging();
153
+ const dragDistance = currentY - startY;
154
+
155
+ if (dragDistance > threshold) {
156
+ this.hide();
157
+ } else {
158
+ modalDialog.style.transform = 'translateY(0)';
159
+ }
160
+ };
161
+
162
+ // Touch events
163
+ dragHandle.addEventListener('touchstart', (e) => {
164
+ startY = (e as TouchEvent).touches[0].clientY;
165
+ startDragging();
166
+ });
167
+
168
+ dragHandle.addEventListener('touchmove', (e) => {
169
+ if (!isDragging) {
170
+ return;
171
+ }
172
+
173
+ currentY = (e as TouchEvent).touches[0].clientY;
174
+ onMove(currentY);
175
+ });
176
+
177
+ dragHandle.addEventListener('touchend', endDrag);
178
+
179
+ // Mouse events
180
+ dragHandle.addEventListener('mousedown', (e) => {
181
+ startY = (e as MouseEvent).clientY;
182
+ startDragging();
183
+
184
+ const onMouseMove = (e) => {
185
+ if (!isDragging) {
186
+ return;
187
+ }
188
+
189
+ currentY = e.clientY;
190
+ onMove(currentY);
191
+ e.preventDefault();
192
+ e.stopPropagation();
193
+ e.stopImmediatePropagation();
194
+ };
195
+
196
+ const onMouseUp = () => {
197
+ endDrag();
198
+ window.removeEventListener('mousemove', onMouseMove);
199
+ window.removeEventListener('mouseup', onMouseUp);
200
+ };
201
+
202
+ window.addEventListener('mousemove', onMouseMove);
203
+ window.addEventListener('mouseup', onMouseUp);
204
+ });
205
+
206
+ // Reset on modal hide
207
+ modal.addEventListener('hidden.bs.modal', () => {
208
+ cancelDragging();
209
+ modalDialog.style.transform = '';
210
+ });
211
+
212
+ (modal as any)._dragBound = true;
213
+ }, 100);
214
+ }
215
+
216
+ treatMobileAsBottomSheet(): boolean {
217
+ if (this.mobileMode == ModalMobileMode.BottomSheetModal) {
218
+ return true;
219
+ } else if (this.mobileMode == null && ModalConfig.defaultMobileMode == ModalMobileMode.BottomSheetModal) {
220
+ return true;
221
+ }
222
+
223
+ return false;
224
+ }
225
+
226
+ treatMobileAsFullScreen(): boolean {
227
+ return (this.mobileMode == ModalMobileMode.FullScreen || (this.mobileMode == null && ModalConfig.defaultMobileMode == ModalMobileMode.FullScreen));
228
+ }
229
+
101
230
  getModalInstance(): BootstrapModal {
102
231
  return BootstrapModal.getOrCreateInstance(this.$refs.modalRoot as Element);
103
232
  }
@@ -112,6 +241,8 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
112
241
  onHidden: args.onHidden,
113
242
  onBeforeShown: args.onBeforeShown,
114
243
  });
244
+
245
+ this.handleMobileModeDragBinding();
115
246
  });
116
247
  }
117
248
 
@@ -133,7 +264,7 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
133
264
  id={this.getFullId()}
134
265
  key={this.getFullId()}
135
266
  ref="modalRoot"
136
- class={`modal fade ${this.mobileFullscreen ? 'mobile-fullscreen ' : ''}${this.cssClass || ''}`}
267
+ class={`modal fade${this.getModalMobileModeCss()} ${this.cssClass || ''}`}
137
268
  role="dialog"
138
269
  aria-labelledby={this.getLabelId()}
139
270
  aria-hidden="true"
@@ -144,6 +275,10 @@ class ModalComponent extends TsxComponent<ModalArgs> implements ModalArgs {
144
275
  >
145
276
  <div class={`modal-dialog${this.getModalSizeCss()}`} role="document">
146
277
  <div class="modal-content">
278
+ <div class="drag-handle text-center">
279
+ <div class="handle-bar"></div>
280
+ </div>
281
+
147
282
  <LoadingIndicator visible={this.blocked} />
148
283
  <div class={`modal-header${this.icon == null ? '' : ' modal-has-headericon'}`}>
149
284
  {this.icon != null && <div class="modal-header-icon">{this.renderModalHeaderIcon()}</div>}
@@ -1,6 +1,6 @@
1
- export const SKILIFT_SVG: string = `
2
- <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000" preserveAspectRatio="xMidYMid meet">
3
- <g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)" fill="currentColor" stroke="none">
4
- <path d="M3911 4254 l-1153 -354 -40 34 c-77 66 -211 76 -290 20 -57 -40 -107 -107 -114 -153 l-6 -38 -1127 -345 -1126 -345 -3 -103 c-2 -94 -1 -102 15 -98 10 3 529 161 1154 353 l1135 347 43 -28 42 -29 -5 -55 c-2 -30 -21 -279 -42 -552 l-38 -498 -360 0 c-200 0 -390 -5 -426 -11 -173 -27 -319 -153 -371 -320 -18 -56 -19 -99 -19 -594 0 -495 1 -538 19 -594 50 -161 183 -281 350 -317 98 -20 1924 -20 2022 0 167 36 300 156 350 317 18 56 19 99 19 588 0 444 -2 536 -16 586 -44 170 -197 307 -374 335 -36 5 -227 10 -426 10 l-360 0 -38 498 c-21 273 -40 522 -43 552 -5 53 -4 56 25 73 40 23 72 69 93 131 l17 49 153 48 c85 26 309 95 499 153 852 260 1595 488 1598 490 1 2 1 48 0 103 l-3 100 -1154 -353z m-1913 -2666 l2 -358 -260 0 -260 0 0 353 c0 195 3 357 7 361 4 3 119 5 257 4 l251 -3 3 -357z m820 0 l2 -358 -260 0 -260 0 0 353 c0 195 3 357 7 361 4 3 119 5 257 4 l251 -3 3 -357z m820 0 l2 -358 -260 0 -260 0 0 353 c0 195 3 357 7 361 4 3 119 5 257 4 l251 -3 3 -357z"/>
5
- </g>
6
- </svg>`;
1
+ export const SKILIFT_SVG: string = `
2
+ <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000" preserveAspectRatio="xMidYMid meet">
3
+ <g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)" fill="currentColor" stroke="none">
4
+ <path d="M3911 4254 l-1153 -354 -40 34 c-77 66 -211 76 -290 20 -57 -40 -107 -107 -114 -153 l-6 -38 -1127 -345 -1126 -345 -3 -103 c-2 -94 -1 -102 15 -98 10 3 529 161 1154 353 l1135 347 43 -28 42 -29 -5 -55 c-2 -30 -21 -279 -42 -552 l-38 -498 -360 0 c-200 0 -390 -5 -426 -11 -173 -27 -319 -153 -371 -320 -18 -56 -19 -99 -19 -594 0 -495 1 -538 19 -594 50 -161 183 -281 350 -317 98 -20 1924 -20 2022 0 167 36 300 156 350 317 18 56 19 99 19 588 0 444 -2 536 -16 586 -44 170 -197 307 -374 335 -36 5 -227 10 -426 10 l-360 0 -38 498 c-21 273 -40 522 -43 552 -5 53 -4 56 25 73 40 23 72 69 93 131 l17 49 153 48 c85 26 309 95 499 153 852 260 1595 488 1598 490 1 2 1 48 0 103 l-3 100 -1154 -353z m-1913 -2666 l2 -358 -260 0 -260 0 0 353 c0 195 3 357 7 361 4 3 119 5 257 4 l251 -3 3 -357z m820 0 l2 -358 -260 0 -260 0 0 353 c0 195 3 357 7 361 4 3 119 5 257 4 l251 -3 3 -357z m820 0 l2 -358 -260 0 -260 0 0 353 c0 195 3 357 7 361 4 3 119 5 257 4 l251 -3 3 -357z"/>
5
+ </g>
6
+ </svg>`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "inviton-powerduck",
3
3
  "type": "module",
4
- "version": "0.0.130",
4
+ "version": "0.0.133",
5
5
  "files": [
6
6
  "app/",
7
7
  "common/",