@propbinder/mobile-design 0.2.17 → 0.2.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@propbinder/mobile-design",
3
- "version": "0.2.17",
3
+ "version": "0.2.22",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^20.3.0 || ^21.0.0",
6
6
  "@angular/core": "^20.3.0 || ^21.0.0"
package/styles/ionic.css CHANGED
@@ -106,7 +106,7 @@ html {
106
106
  html,
107
107
  body {
108
108
  /* Background color must match theme-color for iOS PWA status bar */
109
- background-color: var(--color-brand-secondary);
109
+ background-color: var(--color-header-surface);
110
110
  color: var(--text-color-default-primary);
111
111
  font-family: 'Brockmann', system-ui, -apple-system, sans-serif;
112
112
 
@@ -122,16 +122,16 @@ body {
122
122
  /* iOS-specific: Purple background for overshoot areas to match dark header */
123
123
  .plt-ios html,
124
124
  .plt-ios body {
125
- background-color: var(--color-brand-secondary) !important;
125
+ background-color: var(--color-header-surface) !important;
126
126
  }
127
127
 
128
128
  .plt-ios ion-app {
129
- background-color: var(--color-brand-secondary) !important;
129
+ background-color: var(--color-header-surface) !important;
130
130
  }
131
131
 
132
132
  /* When modal opens, ensure purple background is maintained */
133
133
  body.backdrop-no-scroll {
134
- background-color: var(--color-brand-secondary) !important;
134
+ background-color: var(--color-header-surface) !important;
135
135
  }
136
136
 
137
137
  /* Ionic Component Styles - Map to Design System */
@@ -139,15 +139,14 @@ body.backdrop-no-scroll {
139
139
 
140
140
  :root {
141
141
  /* Override Ionic's primary color to use our brand color */
142
- --ion-color-primary: var(--color-brand-base);
143
- --ion-color-primary-rgb: 107, 95, 245;
144
- --ion-color-primary-contrast: #ffffff;
145
- --ion-color-primary-contrast-rgb: 255, 255, 255;
146
- --ion-color-primary-shade: var(--color-brand-base-hover);
147
- --ion-color-primary-tint: var(--color-brand-base);
142
+ /* Note: RGB values and hover/active states are set dynamically by WhitelabelService */
143
+ --ion-color-primary: var(--color-accent);
144
+ --ion-color-primary-contrast: var(--color-on-accent);
145
+ --ion-color-primary-shade: var(--color-accent-hover);
146
+ --ion-color-primary-tint: var(--color-accent);
148
147
 
149
148
  /* Ionic component defaults */
150
- --ion-background-color: var(--color-brand-secondary);
149
+ --ion-background-color: var(--color-header-surface);
151
150
  --ion-text-color: var(--text-color-default-primary);
152
151
  }
153
152
 
@@ -166,17 +165,17 @@ ion-content {
166
165
 
167
166
  /* iOS: Set base ion-content background to brand secondary for pages */
168
167
  .plt-ios ion-content {
169
- background: var(--color-brand-secondary) !important;
168
+ background: var(--color-header-surface) !important;
170
169
  }
171
170
 
172
171
  /* iOS: Also target any inner background parts */
173
172
  .plt-ios ion-content::part(background) {
174
- background: var(--color-brand-secondary) !important;
173
+ background: var(--color-header-surface) !important;
175
174
  }
176
175
 
177
176
  /* iOS: Target the inner container if it exists */
178
177
  .plt-ios ion-content .inner-scroll {
179
- background: var(--color-brand-secondary) !important;
178
+ background: var(--color-header-surface) !important;
180
179
  }
181
180
 
182
181
  /* Default: Block browser overscroll on all platforms */
@@ -202,18 +201,18 @@ ion-content::part(scroll)::-webkit-scrollbar {
202
201
  overscroll-behavior-y: contain;
203
202
  /* iOS: Set scroll container background to match brand secondary */
204
203
  /* This prevents white background from showing when header fades on scroll */
205
- background: var(--color-brand-secondary) !important;
204
+ background: var(--color-header-surface) !important;
206
205
  }
207
206
 
208
207
  .plt-ios .ion-page {
209
208
  overscroll-behavior-y: contain;
210
209
  /* Set page background to brand secondary to match header on iOS */
211
- background: var(--color-brand-secondary) !important;
210
+ background: var(--color-header-surface) !important;
212
211
  }
213
212
 
214
213
  /* iOS-specific: Override ion-content background for pages (not modals) */
215
214
  .plt-ios .ion-page > ion-content {
216
- --background: var(--color-brand-secondary);
215
+ --background: var(--color-header-surface);
217
216
  }
218
217
 
219
218
  /* iOS: Ensure modal content stays with neutral background */
@@ -233,13 +232,33 @@ ion-content::part(scroll)::-webkit-scrollbar {
233
232
  background: var(--color-background-neutral-primary) !important;
234
233
  }
235
234
 
235
+ /* Exception: Lightbox modals should have black background */
236
+ .plt-ios ion-modal .lightbox-content.pdf-viewer,
237
+ .plt-ios ion-modal .lightbox-content.pdf-viewer::part(scroll),
238
+ .plt-ios ion-modal .lightbox-content.pdf-viewer::part(background),
239
+ .plt-ios ion-modal .lightbox-content.pdf-viewer .inner-scroll {
240
+ background: #000000 !important;
241
+ }
242
+
243
+ /* Also ensure lightbox is black on all platforms */
244
+ ion-modal .lightbox-content.pdf-viewer {
245
+ --background: #000000 !important;
246
+ background: #000000 !important;
247
+ }
248
+
249
+ ion-modal .lightbox-content.pdf-viewer::part(scroll),
250
+ ion-modal .lightbox-content.pdf-viewer::part(background),
251
+ ion-modal .lightbox-content.pdf-viewer .inner-scroll {
252
+ background: #000000 !important;
253
+ }
254
+
236
255
  ion-footer {
237
256
  box-shadow: none;
238
257
  }
239
258
 
240
259
  ion-router-outlet {
241
- --background: var(--color-brand-secondary);
242
- background: var(--color-brand-secondary);
260
+ --background: var(--color-header-surface);
261
+ background: var(--color-header-surface);
243
262
  }
244
263
 
245
264
  ion-refresher {
@@ -253,11 +272,11 @@ ion-refresher-content {
253
272
 
254
273
  /* Force spinner color to brand */
255
274
  ion-spinner {
256
- --color: var(--color-brand-base) !important;
257
- color: var(--color-brand-base) !important;
275
+ --color: var(--color-accent) !important;
276
+ color: var(--color-accent) !important;
258
277
  }
259
278
 
260
- ion-modal {
279
+ ion-modal:not(.ds-bottom-sheet) {
261
280
  --background: var(--color-background-neutral-primary);
262
281
  --border-radius: 16px;
263
282
  --box-shadow: var(--box-shadow-lg);
@@ -267,7 +286,7 @@ ion-modal {
267
286
  }
268
287
 
269
288
  /* Prevent modal container from resizing when keyboard appears */
270
- ion-modal::part(content) {
289
+ ion-modal:not(.ds-bottom-sheet)::part(content) {
271
290
  position: fixed !important;
272
291
  height: 100% !important;
273
292
  max-height: 100vh !important;
@@ -284,7 +303,7 @@ ion-action-sheet {
284
303
  --color: var(--text-color-default-primary);
285
304
  --button-background: var(--color-background-neutral-secondary);
286
305
  --button-background-hover: var(--color-background-neutral-tertiary);
287
- --button-background-selected: var(--color-background-brand);
306
+ --button-background-selected: var(--color-accent);
288
307
  --button-color: var(--text-color-default-primary);
289
308
  }
290
309
 
@@ -310,9 +329,15 @@ ion-toast {
310
329
  --box-shadow: 0px -2px 24px rgba(0, 0, 0, 0.12);
311
330
  --backdrop-opacity: 0.4;
312
331
  transition: --backdrop-opacity 0.3s ease;
313
- /* Modal at top:0 so backdrop covers full screen including status bar */
314
- top: 0;
315
- height: 100%;
332
+
333
+ /* Position the modal container to fill screen */
334
+ top: 0 !important;
335
+ height: 100% !important;
336
+
337
+ /* Align the actual sheet at the bottom */
338
+ display: flex;
339
+ flex-direction: column;
340
+ justify-content: flex-end;
316
341
  }
317
342
 
318
343
  /* Backdrop styling */
@@ -330,18 +355,21 @@ ion-toast {
330
355
  margin-bottom: 8px;
331
356
  }
332
357
 
333
- /* Content area styling */
358
+ /* Content area styling - Support auto-height by default for sheets */
334
359
  .ds-bottom-sheet::part(content) {
335
360
  /* Offset content below status bar (backdrop still covers full screen) */
336
361
  margin-top: var(--app-sheet-top-offset);
337
362
  border-radius: var(--border-radius) var(--border-radius) 0 0;
338
363
  background: var(--color-background-neutral-primary, #ffffff);
339
364
  box-shadow: var(--box-shadow);
340
- position: absolute !important;
341
- top: 0 !important;
342
- bottom: 0 !important;
343
- height: 100% !important;
344
- max-height: 100% !important;
365
+
366
+ /* Auto-height logic: Only as tall as content */
367
+ height: auto !important;
368
+ max-height: calc(100dvh - var(--app-sheet-top-offset)) !important;
369
+
370
+ /* Sit at the bottom of the flex container */
371
+ position: relative !important;
372
+ margin-top: auto !important;
345
373
  }
346
374
 
347
375
  /* Remove border radius when fully expanded */
@@ -378,48 +406,27 @@ ion-toast {
378
406
  Make action sheets auto-size to their content
379
407
  ============================================ */
380
408
 
381
- /* Auto-height modal - override base bottom sheet styles */
382
- .ds-bottom-sheet.auto-height {
383
- top: 0 !important;
384
- height: 100% !important;
385
- --height: fit-content;
386
- --max-height: 80vh;
387
- display: flex;
388
- align-items: flex-end;
389
- }
390
-
391
- .ds-bottom-sheet.auto-height .modal-wrapper {
392
- position: relative !important;
393
- bottom: auto !important;
394
- left: auto !important;
395
- right: auto !important;
396
- height: auto !important;
397
- max-height: 80vh !important;
398
- top: auto !important;
399
- width: 100%;
400
- }
401
-
402
- .ds-bottom-sheet.auto-height::part(content) {
403
- position: relative !important;
404
- height: auto !important;
405
- max-height: 80vh !important;
406
- top: auto !important;
407
- bottom: auto !important;
408
- }
409
+ /* Auto-height behavior is now part of .ds-bottom-sheet base */
409
410
 
410
411
  /* Ensure action sheet component sizes naturally */
411
- .ds-bottom-sheet.auto-height ds-mobile-actions-bottom-sheet {
412
+ .ds-bottom-sheet ds-mobile-actions-bottom-sheet {
412
413
  display: block;
413
414
  height: auto;
414
415
  }
415
416
 
416
417
  /* Ensure action list scrolls if needed */
417
- .ds-bottom-sheet.auto-height .actions-list {
418
- max-height: calc(80vh - 80px); /* Account for handle, padding, and safe area */
418
+ .ds-bottom-sheet .actions-list {
419
+ max-height: calc(85dvh - 80px); /* Account for handle, padding, and safe area */
419
420
  overflow-y: auto;
420
421
  -webkit-overflow-scrolling: touch;
421
422
  }
422
423
 
424
+ /* Ensure ion-content doesn't force 100% height in sheets */
425
+ .ds-bottom-sheet ion-content {
426
+ height: auto !important;
427
+ --height: auto;
428
+ }
429
+
423
430
  /* ============================================
424
431
  Mobile Modal Styles (Generic Modal Service)
425
432
  ============================================ */
@@ -834,3 +841,23 @@ ion-app ion-router-outlet.ion-page-hidden {
834
841
 
835
842
  /* Dark mode support removed - modals should not change based on system dark mode */
836
843
 
844
+ /* ============================================
845
+ GLOBAL BUTTON INTERACTIVE STATES
846
+ Consistent button behavior across all ds-button instances
847
+ ============================================ */
848
+
849
+ /* Base transition */
850
+ ds-button .btn {
851
+ transition: all 0.2s ease !important;
852
+ }
853
+
854
+ /* Active/pressed/click state - scale down slightly */
855
+ ds-button .btn:active:not(:disabled) {
856
+ transform: scale(0.98) !important;
857
+ }
858
+
859
+ /* FORCE hover background color directly - only for primary variant */
860
+ ds-button[variant="primary"]:hover .btn {
861
+ background-color: var(--color-accent-hover) !important;
862
+ }
863
+
@@ -77,7 +77,7 @@
77
77
 
78
78
  /* Section Headlines */
79
79
  .section-headline {
80
- font-size: var(--font-size-sm);
80
+ font-size: var(--font-size-base);
81
81
  font-weight: 600;
82
82
  color: var(--text-color-default-primary);
83
83
  padding: 16px 0;
@@ -14,7 +14,7 @@
14
14
  align-items: center;
15
15
  height: 100%;
16
16
  /* Solid background to cover overlay from page underneath during transitions */
17
- background: var(--color-secondary-surface);
17
+ background: var(--color-header-surface);
18
18
  width: 100%;
19
19
  }
20
20
 
@@ -23,7 +23,7 @@
23
23
  ============================================ */
24
24
 
25
25
  :host ion-header {
26
- background: var(--color-brand-secondary);
26
+ background: var(--color-header-surface);
27
27
  box-shadow: none;
28
28
  height: 72px;
29
29
  min-height: 72px;
@@ -31,7 +31,7 @@
31
31
  }
32
32
 
33
33
  :host ion-header ion-toolbar {
34
- --background: var(--color-brand-secondary);
34
+ --background: var(--color-header-surface);
35
35
  --border-width: 0;
36
36
  --box-shadow: none;
37
37
  --padding-top: 0;
@@ -78,7 +78,7 @@
78
78
  display: flex;
79
79
  align-items: center;
80
80
  justify-content: space-between;
81
- background: var(--color-brand-secondary);
81
+ background: var(--color-header-surface);
82
82
  position: relative;
83
83
  }
84
84
 
@@ -91,10 +91,10 @@
91
91
  transform: translateX(-50%);
92
92
  font-size: var(--font-size-base);
93
93
  font-weight: 600;
94
- color: white;
94
+ color: var(--color-header-content);
95
95
  margin: 0;
96
96
  padding: 0;
97
- --color: white;
97
+ --color: var(--color-header-content);
98
98
  }
99
99
 
100
100
  /* Scroll behavior for header-details title (hidden initially, shows on scroll) */
@@ -122,7 +122,7 @@
122
122
  align-items: center;
123
123
  justify-content: center;
124
124
  cursor: pointer;
125
- color: white;
125
+ color: var(--color-header-content);
126
126
  transition: opacity var(--transition-duration-fast, 0.2s) var(--ease-smooth, ease);
127
127
  z-index: 10;
128
128
  position: relative;
@@ -143,7 +143,7 @@
143
143
  ============================================ */
144
144
 
145
145
  :host ion-content {
146
- --background: var(--color-brand-secondary);
146
+ --background: var(--color-header-surface);
147
147
  --padding-top: 0;
148
148
  --padding-start: 0;
149
149
  --padding-end: 0;
@@ -196,7 +196,7 @@
196
196
  }
197
197
 
198
198
  :host ion-refresher-content {
199
- --color: white;
199
+ --color: var(--color-header-content);
200
200
  }
201
201
 
202
202
  /* ============================================
@@ -213,6 +213,7 @@
213
213
  flex-direction: column;
214
214
  background: var(--color-background-neutral-primary);
215
215
  border-radius: 24px 24px 0 0;
216
+ overflow: scroll;
216
217
 
217
218
  /* Visual styling for iOS overshoot - extend background below using box-shadow */
218
219
  transform: translateZ(0);
@@ -220,9 +221,11 @@
220
221
  isolation: isolate;
221
222
  box-shadow: 0 300px 0 0 var(--color-background-neutral-primary);
222
223
 
223
- /* Fixed 20px horizontal padding globally */
224
- padding: 20px;
225
- /* Add bottom padding on mobile to account for fixed tab bar */
224
+ /* No top padding - ds-mobile-section provides its own */
225
+ padding-top: 0;
226
+ padding-left: var(--content-wrapper-padding, 20px);
227
+ padding-right: var(--content-wrapper-padding, 20px);
228
+ /* Bottom padding ALWAYS preserved for safe area and tab bar */
226
229
  padding-bottom: calc(var(--mobile-content-spacing) + var(--mobile-tab-bar-height) + env(safe-area-inset-bottom, 0px));
227
230
  }
228
231
 
@@ -238,7 +241,10 @@
238
241
 
239
242
  @media (min-width: 768px) {
240
243
  :host .content-wrapper {
241
- padding: 32px 20px;
244
+ /* Remove top padding since ds-mobile-section provides its own */
245
+ padding-top: 0;
246
+ padding-left: var(--content-wrapper-padding, 20px);
247
+ padding-right: var(--content-wrapper-padding, 20px);
242
248
  }
243
249
  }
244
250
 
@@ -247,7 +253,7 @@
247
253
  ============================================ */
248
254
 
249
255
  :host .header-expandable {
250
- background: var(--color-brand-secondary);
256
+ background: var(--color-header-surface);
251
257
  padding: 32px 20px 24px 20px;
252
258
  color: var(--header-content-color, white);
253
259
  position: sticky;