@propbinder/mobile-design 0.2.31 → 0.2.34
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/index.d.ts
CHANGED
|
@@ -1158,7 +1158,7 @@ declare class DsMobileContentComponent {
|
|
|
1158
1158
|
*/
|
|
1159
1159
|
declare class SectionHeaderComponent {
|
|
1160
1160
|
/** Width of the header placeholder */
|
|
1161
|
-
width: _angular_core.InputSignal<"
|
|
1161
|
+
width: _angular_core.InputSignal<"full" | "half" | "third">;
|
|
1162
1162
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SectionHeaderComponent, never>;
|
|
1163
1163
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SectionHeaderComponent, "section-header", never, { "width": { "alias": "width"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
1164
1164
|
}
|
package/package.json
CHANGED
package/styles/ionic.css
CHANGED
|
@@ -22,54 +22,46 @@
|
|
|
22
22
|
:root {
|
|
23
23
|
/* Mobile-specific brand color for headers/backgrounds */
|
|
24
24
|
--color-brand-secondary: #221a4c;
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
/* Ionic Keyboard Appearance - force light theme */
|
|
27
27
|
--ion-keyboard-color: #ffffff;
|
|
28
28
|
--ion-keyboard-background: #ffffff;
|
|
29
29
|
--ion-keyboard-text-color: #000000;
|
|
30
30
|
color-scheme: light;
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
/* Layout - Mobile Navigation */
|
|
33
33
|
--mobile-tab-bar-height: 64px;
|
|
34
34
|
--mobile-content-spacing: 20px;
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
/* Tab Bar Height - Used for FAB positioning and other layout calculations */
|
|
37
37
|
/* This is set by ds-mobile-tab-bar and consumed by ds-mobile-fab */
|
|
38
38
|
--ds-tab-bar-height: 64px;
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
/* ============================================
|
|
41
41
|
SPRING ANIMATIONS
|
|
42
42
|
Physics-based easing curves with natural bounce
|
|
43
43
|
============================================ */
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
/* Spring Curves */
|
|
46
|
-
--spring-curve-bouncy: linear(
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
--spring-curve-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
--spring-curve-snappy: linear(
|
|
55
|
-
0, 0.3, 0.7, 1.05, 0.98, 1
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
--spring-curve-smooth: linear(
|
|
59
|
-
0, 0.215, 0.61, 0.855, 1
|
|
60
|
-
);
|
|
61
|
-
|
|
46
|
+
--spring-curve-bouncy: linear(0, 0.0209, 0.0772, 0.1598, 0.2602, 0.3709, 0.4854, 0.5984, 0.7056, 0.8038, 0.8908, 0.9653, 1.0267, 1.075, 1.111, 1.1354, 1.1497, 1.1551, 1.1532, 1.1455, 1.1335, 1.1184, 1.1014, 1.0837, 1.066, 1.0492, 1.0336, 1.0197, 1.0077, 0.9977, 0.9898, 0.9838, 0.9796, 0.9771, 0.976, 0.9761, 0.9771, 0.9788, 0.9811, 0.9837, 0.9864, 0.9892, 0.9918, 0.9943, 0.9965, 0.9984, 1.0001, 1.0013, 1.0023, 1.003, 1.0035, 1);
|
|
47
|
+
|
|
48
|
+
--spring-curve-gentle: linear(0, 0.2, 0.5, 0.8, 1.02, 1.01, 1);
|
|
49
|
+
|
|
50
|
+
--spring-curve-snappy: linear(0, 0.3, 0.7, 1.05, 0.98, 1);
|
|
51
|
+
|
|
52
|
+
--spring-curve-smooth: linear(0, 0.215, 0.61, 0.855, 1);
|
|
53
|
+
|
|
62
54
|
/* Spring Durations */
|
|
63
55
|
--spring-duration-fast: 400ms;
|
|
64
56
|
--spring-duration-medium: 700ms;
|
|
65
57
|
--spring-duration-slow: 1000ms;
|
|
66
|
-
|
|
58
|
+
|
|
67
59
|
/* Spring Presets (curve + duration) */
|
|
68
60
|
--spring-bouncy: var(--spring-duration-medium) var(--spring-curve-bouncy);
|
|
69
61
|
--spring-gentle: var(--spring-duration-fast) var(--spring-curve-gentle);
|
|
70
62
|
--spring-snappy: var(--spring-duration-fast) var(--spring-curve-snappy);
|
|
71
63
|
--spring-smooth: var(--spring-duration-medium) var(--spring-curve-smooth);
|
|
72
|
-
|
|
64
|
+
|
|
73
65
|
/* ============================================
|
|
74
66
|
SAFE AREA / STATUS BAR CONFIGURATION
|
|
75
67
|
|
|
@@ -83,12 +75,12 @@
|
|
|
83
75
|
1. app.ts: StatusBar.setOverlaysWebView({ overlay: true/false })
|
|
84
76
|
2. These CSS variables below
|
|
85
77
|
============================================ */
|
|
86
|
-
|
|
78
|
+
|
|
87
79
|
/* Sheet/modal top offset - positions content below status bar area */
|
|
88
80
|
/* Uses max() to ensure at least 32px offset even on devices without notch */
|
|
89
81
|
/* +12px adds breathing room below the status bar */
|
|
90
82
|
--app-sheet-top-offset: calc(max(32px, env(safe-area-inset-top, 32px)) + 12px);
|
|
91
|
-
|
|
83
|
+
|
|
92
84
|
/* Header top offset - used to fine-tune header position on iOS with overlay: true */
|
|
93
85
|
/* On web (no safe area), this should be 0px. On iOS, it compensates for status bar overlap */
|
|
94
86
|
--app-header-top-offset: max(0px, calc(env(safe-area-inset-top, 0px) - 16px));
|
|
@@ -109,13 +101,13 @@ body {
|
|
|
109
101
|
background-color: var(--color-header-surface);
|
|
110
102
|
color: var(--text-color-default-primary);
|
|
111
103
|
font-family: 'Brockmann', system-ui, -apple-system, sans-serif;
|
|
112
|
-
|
|
104
|
+
|
|
113
105
|
/* Ensure full height for iOS PWA */
|
|
114
106
|
height: 100%;
|
|
115
107
|
width: 100%;
|
|
116
108
|
margin: 0;
|
|
117
109
|
padding: 0;
|
|
118
|
-
|
|
110
|
+
|
|
119
111
|
/* Don't add padding to html/body - let Ionic components handle safe areas */
|
|
120
112
|
}
|
|
121
113
|
|
|
@@ -127,6 +119,11 @@ body {
|
|
|
127
119
|
|
|
128
120
|
.plt-ios ion-app {
|
|
129
121
|
background-color: var(--color-header-surface) !important;
|
|
122
|
+
height: 100dvh;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
ion-app {
|
|
126
|
+
height: 100dvh;
|
|
130
127
|
}
|
|
131
128
|
|
|
132
129
|
/* When modal opens, ensure purple background is maintained */
|
|
@@ -144,7 +141,7 @@ body.backdrop-no-scroll {
|
|
|
144
141
|
--ion-color-primary-contrast: var(--color-on-accent);
|
|
145
142
|
--ion-color-primary-shade: var(--color-accent-hover);
|
|
146
143
|
--ion-color-primary-tint: var(--color-accent);
|
|
147
|
-
|
|
144
|
+
|
|
148
145
|
/* Ionic component defaults */
|
|
149
146
|
--ion-background-color: var(--color-header-surface);
|
|
150
147
|
--ion-text-color: var(--text-color-default-primary);
|
|
@@ -183,8 +180,10 @@ ion-content::part(scroll) {
|
|
|
183
180
|
overscroll-behavior-y: none;
|
|
184
181
|
-webkit-overflow-scrolling: touch;
|
|
185
182
|
/* Hide scrollbar while maintaining scroll functionality */
|
|
186
|
-
scrollbar-width: none;
|
|
187
|
-
|
|
183
|
+
scrollbar-width: none;
|
|
184
|
+
/* Firefox */
|
|
185
|
+
-ms-overflow-style: none;
|
|
186
|
+
/* IE/Edge */
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
/* Hide scrollbar for WebKit browsers (Chrome, Safari, iOS) */
|
|
@@ -280,16 +279,17 @@ ion-modal:not(.ds-bottom-sheet) {
|
|
|
280
279
|
--background: var(--color-background-neutral-primary);
|
|
281
280
|
--border-radius: 16px;
|
|
282
281
|
--box-shadow: var(--box-shadow-lg);
|
|
283
|
-
|
|
284
|
-
height:
|
|
285
|
-
|
|
282
|
+
--height: auto;
|
|
283
|
+
max-height: 100dvh;
|
|
284
|
+
height: 100dvh !important;
|
|
286
285
|
}
|
|
287
286
|
|
|
288
287
|
/* Prevent modal container from resizing when keyboard appears */
|
|
289
288
|
ion-modal:not(.ds-bottom-sheet)::part(content) {
|
|
290
289
|
position: fixed !important;
|
|
291
|
-
height:
|
|
292
|
-
|
|
290
|
+
max-height: 100dvh !important;
|
|
291
|
+
/* Ensure content doesn't get cut off by keyboard or safe area */
|
|
292
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
/* Prevent ion-content inside modals from resizing */
|
|
@@ -329,7 +329,7 @@ ion-toast {
|
|
|
329
329
|
--box-shadow: 0px -2px 24px rgba(0, 0, 0, 0.12);
|
|
330
330
|
--backdrop-opacity: 0.4;
|
|
331
331
|
transition: --backdrop-opacity 0.3s ease;
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
/* Position the modal container to fill screen */
|
|
334
334
|
top: 0 !important;
|
|
335
335
|
height: 100% !important;
|
|
@@ -416,7 +416,8 @@ ion-toast {
|
|
|
416
416
|
|
|
417
417
|
/* Ensure action list scrolls if needed */
|
|
418
418
|
.ds-bottom-sheet .actions-list {
|
|
419
|
-
max-height: calc(85dvh - 80px);
|
|
419
|
+
max-height: calc(85dvh - 80px);
|
|
420
|
+
/* Account for handle, padding, and safe area */
|
|
420
421
|
overflow-y: auto;
|
|
421
422
|
-webkit-overflow-scrolling: touch;
|
|
422
423
|
}
|
|
@@ -544,6 +545,7 @@ ion-toast {
|
|
|
544
545
|
from {
|
|
545
546
|
transform: translateY(100%);
|
|
546
547
|
}
|
|
548
|
+
|
|
547
549
|
to {
|
|
548
550
|
transform: translateY(0);
|
|
549
551
|
}
|
|
@@ -553,6 +555,7 @@ ion-toast {
|
|
|
553
555
|
from {
|
|
554
556
|
transform: translateY(0);
|
|
555
557
|
}
|
|
558
|
+
|
|
556
559
|
to {
|
|
557
560
|
transform: translateY(100%);
|
|
558
561
|
}
|
|
@@ -562,6 +565,7 @@ ion-toast {
|
|
|
562
565
|
from {
|
|
563
566
|
opacity: 0;
|
|
564
567
|
}
|
|
568
|
+
|
|
565
569
|
to {
|
|
566
570
|
opacity: 1;
|
|
567
571
|
}
|
|
@@ -571,6 +575,7 @@ ion-toast {
|
|
|
571
575
|
from {
|
|
572
576
|
opacity: 1;
|
|
573
577
|
}
|
|
578
|
+
|
|
574
579
|
to {
|
|
575
580
|
opacity: 0;
|
|
576
581
|
}
|
|
@@ -588,6 +593,7 @@ ion-toast {
|
|
|
588
593
|
|
|
589
594
|
/* Accessibility: Reduced motion */
|
|
590
595
|
@media (prefers-reduced-motion: reduce) {
|
|
596
|
+
|
|
591
597
|
.ds-mobile-modal.modal-card-enter-active,
|
|
592
598
|
.ds-mobile-modal.modal-card-leave-active,
|
|
593
599
|
.ds-mobile-modal.modal-sheet-enter-active,
|
|
@@ -616,11 +622,11 @@ ion-modal.ds-modal-base {
|
|
|
616
622
|
--width: 100%;
|
|
617
623
|
--max-width: 640px;
|
|
618
624
|
/* Subtract top offset from total height to avoid bottom clipping */
|
|
619
|
-
|
|
620
|
-
|
|
625
|
+
--height: calc(100dvh - var(--app-sheet-top-offset, 24px)) !important;
|
|
626
|
+
--max-height: calc(100dvh - var(--app-sheet-top-offset, 24px)) !important;
|
|
621
627
|
--border-radius: 16px 16px 0 0;
|
|
622
628
|
display: flex !important;
|
|
623
|
-
|
|
629
|
+
align-items: flex-end !important;
|
|
624
630
|
}
|
|
625
631
|
|
|
626
632
|
ion-modal.ds-modal-base::part(content) {
|
|
@@ -630,10 +636,10 @@ ion-modal.ds-modal-base::part(content) {
|
|
|
630
636
|
max-width: 640px;
|
|
631
637
|
margin: 0 auto;
|
|
632
638
|
/* Reset Ionic's default top offset and stick to bottom */
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
639
|
+
top: auto !important;
|
|
640
|
+
bottom: 0 !important;
|
|
641
|
+
height: 100% !important;
|
|
642
|
+
position: relative !important;
|
|
637
643
|
}
|
|
638
644
|
|
|
639
645
|
/* Auto-height support for base modals */
|
|
@@ -649,13 +655,14 @@ ion-modal.ds-modal-base::part(content) {
|
|
|
649
655
|
position: relative !important;
|
|
650
656
|
top: auto !important;
|
|
651
657
|
max-height: calc(100dvh - var(--app-sheet-top-offset, 24px)) !important;
|
|
652
|
-
|
|
658
|
+
bottom: 0 !important;
|
|
653
659
|
}
|
|
654
660
|
|
|
655
661
|
.ds-modal-base.auto-height ion-content {
|
|
656
662
|
height: auto !important;
|
|
657
663
|
--height: auto;
|
|
658
664
|
}
|
|
665
|
+
|
|
659
666
|
.ds-modal-base::part(backdrop) {
|
|
660
667
|
background: rgba(0, 0, 0, 0.4);
|
|
661
668
|
backdrop-filter: blur(4px);
|
|
@@ -673,7 +680,8 @@ ion-modal.ds-modal-base::part(content) {
|
|
|
673
680
|
--background: var(--color-background-neutral-primary, #ffffff);
|
|
674
681
|
--width: 100%;
|
|
675
682
|
--max-width: 640px;
|
|
676
|
-
--height: 100dvh;
|
|
683
|
+
--height: 100dvh;
|
|
684
|
+
/* Full viewport height - content top offset creates gap */
|
|
677
685
|
--border-radius: 16px 16px 0 0;
|
|
678
686
|
}
|
|
679
687
|
|
|
@@ -766,7 +774,8 @@ ion-app ion-router-outlet.ion-page-hidden {
|
|
|
766
774
|
--background: var(--color-background-neutral-primary, #ffffff);
|
|
767
775
|
--width: 100%;
|
|
768
776
|
--max-width: 640px;
|
|
769
|
-
--height: 100dvh;
|
|
777
|
+
--height: 100dvh;
|
|
778
|
+
/* Full viewport height - content top offset creates gap */
|
|
770
779
|
--border-radius: 16px 16px 0 0;
|
|
771
780
|
}
|
|
772
781
|
|
|
@@ -801,7 +810,8 @@ ion-app ion-router-outlet.ion-page-hidden {
|
|
|
801
810
|
--background: var(--color-background-neutral-primary, #ffffff);
|
|
802
811
|
--width: 100%;
|
|
803
812
|
--max-width: 640px;
|
|
804
|
-
--height: 100dvh;
|
|
813
|
+
--height: 100dvh;
|
|
814
|
+
/* Use dynamic viewport height instead of 100% */
|
|
805
815
|
--border-radius: 16px 16px 0 0;
|
|
806
816
|
margin-top: var(--app-sheet-top-offset);
|
|
807
817
|
}
|
|
@@ -830,15 +840,15 @@ ion-app ion-router-outlet.ion-page-hidden {
|
|
|
830
840
|
.ds-handbook-detail-modal {
|
|
831
841
|
--background: var(--color-background-neutral-primary-dark, #1a1a1a);
|
|
832
842
|
}
|
|
833
|
-
|
|
843
|
+
|
|
834
844
|
.ds-handbook-detail-modal::part(content) {
|
|
835
845
|
background: var(--color-background-neutral-primary-dark, #1a1a1a);
|
|
836
846
|
}
|
|
837
|
-
|
|
847
|
+
|
|
838
848
|
.ds-handbook-detail-modal::part(backdrop) {
|
|
839
849
|
background: rgba(0, 0, 0, 0.6);
|
|
840
850
|
}
|
|
841
|
-
|
|
851
|
+
|
|
842
852
|
.ds-handbook-detail-modal ion-content {
|
|
843
853
|
--background: var(--color-background-neutral-primary-dark, #1a1a1a);
|
|
844
854
|
}
|
|
@@ -852,7 +862,8 @@ ion-app ion-router-outlet.ion-page-hidden {
|
|
|
852
862
|
--background: var(--color-background-neutral-primary, #ffffff);
|
|
853
863
|
--width: 100%;
|
|
854
864
|
--max-width: 640px;
|
|
855
|
-
--height: 100dvh;
|
|
865
|
+
--height: 100dvh;
|
|
866
|
+
/* Full viewport height - content top offset creates gap */
|
|
856
867
|
--border-radius: 16px 16px 0 0;
|
|
857
868
|
}
|
|
858
869
|
|
|
@@ -897,5 +908,4 @@ ds-button .btn:active:not(:disabled) {
|
|
|
897
908
|
/* FORCE hover background color directly - only for primary variant */
|
|
898
909
|
ds-button[variant="primary"]:hover .btn {
|
|
899
910
|
background-color: var(--color-accent-hover) !important;
|
|
900
|
-
}
|
|
901
|
-
|
|
911
|
+
}
|