tin-spa 20.14.99 → 20.14.113

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.
Files changed (51) hide show
  1. package/core/index.d.ts +3033 -0
  2. package/fesm2022/tin-spa-accounting.module-Cg4vWaJE.mjs +2231 -0
  3. package/fesm2022/tin-spa-accounting.module-Cg4vWaJE.mjs.map +1 -0
  4. package/fesm2022/tin-spa-agent-page.component-DJvMPjCQ.mjs +39 -0
  5. package/fesm2022/tin-spa-agent-page.component-DJvMPjCQ.mjs.map +1 -0
  6. package/fesm2022/tin-spa-agent.component-D0CGGnGZ.mjs +1379 -0
  7. package/fesm2022/tin-spa-agent.component-D0CGGnGZ.mjs.map +1 -0
  8. package/fesm2022/tin-spa-assets.module-qIWNwJ2E.mjs +167 -0
  9. package/fesm2022/tin-spa-assets.module-qIWNwJ2E.mjs.map +1 -0
  10. package/fesm2022/tin-spa-core.mjs +13628 -0
  11. package/fesm2022/tin-spa-core.mjs.map +1 -0
  12. package/fesm2022/tin-spa-general-erp.module-CoYxceLj.mjs +138 -0
  13. package/fesm2022/tin-spa-general-erp.module-CoYxceLj.mjs.map +1 -0
  14. package/fesm2022/tin-spa-hr.module-CKPZ9ZOj.mjs +134 -0
  15. package/fesm2022/tin-spa-hr.module-CKPZ9ZOj.mjs.map +1 -0
  16. package/fesm2022/tin-spa-http.mjs +117 -0
  17. package/fesm2022/tin-spa-http.mjs.map +1 -0
  18. package/fesm2022/tin-spa-inventory.module-DRKAcNau.mjs +338 -0
  19. package/fesm2022/tin-spa-inventory.module-DRKAcNau.mjs.map +1 -0
  20. package/fesm2022/tin-spa-keys.mjs +14 -0
  21. package/fesm2022/tin-spa-keys.mjs.map +1 -0
  22. package/fesm2022/tin-spa-landing.mjs +189 -0
  23. package/fesm2022/tin-spa-landing.mjs.map +1 -0
  24. package/fesm2022/tin-spa-loans.module-BTDmgrWo.mjs +115 -0
  25. package/fesm2022/tin-spa-loans.module-BTDmgrWo.mjs.map +1 -0
  26. package/fesm2022/tin-spa-login.mjs +719 -0
  27. package/fesm2022/tin-spa-login.mjs.map +1 -0
  28. package/fesm2022/tin-spa-manufacturing.module-CHta6oV_.mjs +96 -0
  29. package/fesm2022/tin-spa-manufacturing.module-CHta6oV_.mjs.map +1 -0
  30. package/fesm2022/tin-spa-map.mjs +750 -0
  31. package/fesm2022/tin-spa-map.mjs.map +1 -0
  32. package/fesm2022/tin-spa-payroll.module-CZ_GO1jF.mjs +847 -0
  33. package/fesm2022/tin-spa-payroll.module-CZ_GO1jF.mjs.map +1 -0
  34. package/fesm2022/tin-spa-purchasing.module-NCdwquaF.mjs +161 -0
  35. package/fesm2022/tin-spa-purchasing.module-NCdwquaF.mjs.map +1 -0
  36. package/fesm2022/tin-spa-sales.module-D0uEGJW7.mjs +1346 -0
  37. package/fesm2022/tin-spa-sales.module-D0uEGJW7.mjs.map +1 -0
  38. package/fesm2022/tin-spa-tenancy-erp.module-GwIv8Wbc.mjs +932 -0
  39. package/fesm2022/tin-spa-tenancy-erp.module-GwIv8Wbc.mjs.map +1 -0
  40. package/fesm2022/tin-spa-tin-spa-Cqe5hYTr.mjs +22576 -0
  41. package/fesm2022/tin-spa-tin-spa-Cqe5hYTr.mjs.map +1 -0
  42. package/fesm2022/tin-spa.mjs +2 -42079
  43. package/fesm2022/tin-spa.mjs.map +1 -1
  44. package/http/index.d.ts +16 -0
  45. package/index.d.ts +588 -4687
  46. package/keys/index.d.ts +4 -0
  47. package/landing/index.d.ts +175 -0
  48. package/login/index.d.ts +141 -0
  49. package/map/index.d.ts +148 -0
  50. package/package.json +25 -1
  51. package/src/tin-styles.css +81 -2
@@ -0,0 +1,4 @@
1
+ declare const AUTH_TOKEN_KEY = "d";
2
+ declare const AUTH_REFRESH_TOKEN_KEY = "g";
3
+
4
+ export { AUTH_REFRESH_TOKEN_KEY, AUTH_TOKEN_KEY };
@@ -0,0 +1,175 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnInit, AfterViewInit, OnDestroy, Injector, ElementRef } from '@angular/core';
3
+ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
4
+ import { Router } from '@angular/router';
5
+
6
+ interface LandingColors {
7
+ primary: string;
8
+ primaryDark: string;
9
+ primaryLight: string;
10
+ secondary: string;
11
+ secondaryLight: string;
12
+ }
13
+ interface LandingBrandOverride {
14
+ svgMarkup: string;
15
+ wordmarkLine1?: string;
16
+ wordmarkLine2?: string;
17
+ }
18
+ interface LandingNavLink {
19
+ label: string;
20
+ target: string;
21
+ }
22
+ interface LandingFeature {
23
+ title: string;
24
+ description: string;
25
+ icon: string;
26
+ color: string;
27
+ }
28
+ interface LandingStep {
29
+ number: string;
30
+ title: string;
31
+ description: string;
32
+ icon: string;
33
+ }
34
+ interface LandingModuleTile {
35
+ name: string;
36
+ icon: string;
37
+ }
38
+ interface LandingModuleGroup {
39
+ category: string;
40
+ tiles: LandingModuleTile[];
41
+ }
42
+ interface LandingMetric {
43
+ value: string;
44
+ label: string;
45
+ }
46
+ interface LandingSecurityItem {
47
+ icon: string;
48
+ title: string;
49
+ description: string;
50
+ }
51
+ interface LandingTestimonial {
52
+ quote: string;
53
+ authorName: string;
54
+ authorRole: string;
55
+ authorInitials: string;
56
+ }
57
+ interface LandingPricingPlan {
58
+ name: string;
59
+ price: string;
60
+ period?: string;
61
+ description: string;
62
+ features: string[];
63
+ ctaLabel: string;
64
+ ctaRoute?: string;
65
+ ctaSection?: string;
66
+ popular?: boolean;
67
+ outline?: boolean;
68
+ }
69
+ interface LandingFooterLink {
70
+ label: string;
71
+ section?: string;
72
+ route?: string;
73
+ }
74
+ interface LandingFooterColumn {
75
+ title: string;
76
+ links: LandingFooterLink[];
77
+ }
78
+ interface LandingConfig {
79
+ appName: string;
80
+ logoSrc: string;
81
+ colors: LandingColors;
82
+ navBrand?: LandingBrandOverride;
83
+ navLinks: LandingNavLink[];
84
+ hero: {
85
+ badge?: string;
86
+ headline: string;
87
+ gradientText: string;
88
+ subtitle: string;
89
+ primaryCTA: string;
90
+ primaryCTARoute?: string;
91
+ secondaryCTA: string;
92
+ secondaryCTASection: string;
93
+ trustSignals: string[];
94
+ layout?: 'centered' | 'split';
95
+ watermarkSvg?: string;
96
+ };
97
+ features: {
98
+ title: string;
99
+ subtitle: string;
100
+ items: LandingFeature[];
101
+ };
102
+ workflow?: {
103
+ title: string;
104
+ subtitle?: string;
105
+ style?: 'steps' | 'road';
106
+ steps: LandingStep[];
107
+ };
108
+ modules?: {
109
+ title: string;
110
+ subtitle: string;
111
+ groups: LandingModuleGroup[];
112
+ };
113
+ metrics?: LandingMetric[];
114
+ security?: {
115
+ title: string;
116
+ subtitle: string;
117
+ items: LandingSecurityItem[];
118
+ };
119
+ testimonials?: {
120
+ title: string;
121
+ subtitle?: string;
122
+ items: LandingTestimonial[];
123
+ };
124
+ pricing?: {
125
+ title: string;
126
+ subtitle?: string;
127
+ plans: LandingPricingPlan[];
128
+ };
129
+ finalCta?: {
130
+ headline: string;
131
+ subtitle: string;
132
+ primaryCTA: string;
133
+ primaryCTARoute?: string;
134
+ secondaryCTA?: string;
135
+ secondaryCTASection?: string;
136
+ };
137
+ footerCompany?: string;
138
+ footerTagline?: string;
139
+ footerBrand?: LandingBrandOverride;
140
+ footerColumns?: LandingFooterColumn[];
141
+ }
142
+ declare const ALSQUARE_SVG_DARK = "<svg viewBox=\"0 0 80 80\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M32 62C17.6 62 6 50.4 6 36S17.6 10 32 10c9.2 0 17.3 4.9 21.8 12.2\" stroke=\"#1a3a7a\" stroke-width=\"9\" stroke-linecap=\"round\" fill=\"none\"/>\n <circle cx=\"32\" cy=\"36\" r=\"10\" fill=\"white\" stroke=\"#1a3a7a\" stroke-width=\"7\"/>\n <circle cx=\"32\" cy=\"36\" r=\"5.5\" fill=\"#e8a020\"/>\n <line x1=\"48\" y1=\"22\" x2=\"48\" y2=\"62\" stroke=\"#1a3a7a\" stroke-width=\"9\" stroke-linecap=\"round\"/>\n <rect x=\"56\" y=\"6\" width=\"7\" height=\"56\" rx=\"3.5\" fill=\"#e8a020\"/>\n <rect x=\"67\" y=\"0\" width=\"6\" height=\"6\" rx=\"1\" fill=\"#1a3a7a\"/>\n <rect x=\"67\" y=\"9\" width=\"6\" height=\"6\" rx=\"1\" fill=\"#1a3a7a\"/>\n <rect x=\"75\" y=\"0\" width=\"5\" height=\"5\" rx=\"1\" fill=\"#1a3a7a\" opacity=\"0.7\"/>\n <rect x=\"75\" y=\"8\" width=\"5\" height=\"5\" rx=\"1\" fill=\"#1a3a7a\" opacity=\"0.5\"/>\n</svg>";
143
+ declare const ALSQUARE_SVG_WHITE = "<svg viewBox=\"0 0 80 80\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M32 62C17.6 62 6 50.4 6 36S17.6 10 32 10c9.2 0 17.3 4.9 21.8 12.2\" stroke=\"#ffffff\" stroke-width=\"9\" stroke-linecap=\"round\" fill=\"none\"/>\n <circle cx=\"32\" cy=\"36\" r=\"10\" fill=\"#0f172a\" stroke=\"#ffffff\" stroke-width=\"7\"/>\n <circle cx=\"32\" cy=\"36\" r=\"5.5\" fill=\"#e8a020\"/>\n <line x1=\"48\" y1=\"22\" x2=\"48\" y2=\"62\" stroke=\"#ffffff\" stroke-width=\"9\" stroke-linecap=\"round\"/>\n <rect x=\"56\" y=\"6\" width=\"7\" height=\"56\" rx=\"3.5\" fill=\"#e8a020\"/>\n <rect x=\"67\" y=\"0\" width=\"6\" height=\"6\" rx=\"1\" fill=\"#ffffff\"/>\n <rect x=\"67\" y=\"9\" width=\"6\" height=\"6\" rx=\"1\" fill=\"#ffffff\"/>\n <rect x=\"75\" y=\"0\" width=\"5\" height=\"5\" rx=\"1\" fill=\"#ffffff\" opacity=\"0.7\"/>\n <rect x=\"75\" y=\"8\" width=\"5\" height=\"5\" rx=\"1\" fill=\"#ffffff\" opacity=\"0.5\"/>\n</svg>";
144
+
145
+ declare class SpaLandingComponent implements OnInit, AfterViewInit, OnDestroy {
146
+ private router;
147
+ private injector;
148
+ private el;
149
+ private sanitizer;
150
+ config: LandingConfig;
151
+ mobileMenuOpen: boolean;
152
+ navScrolled: boolean;
153
+ restoring: boolean;
154
+ currentYear: number;
155
+ private observer;
156
+ constructor(router: Router, injector: Injector, // Changed (landing-first L1): the resume services are resolved AFTER a dynamic import, so this entry point names no primary symbol
157
+ el: ElementRef, sanitizer: DomSanitizer);
158
+ get safeNavBrandSvg(): SafeHtml | null;
159
+ get safeHeroWatermarkSvg(): SafeHtml | null;
160
+ get safeFooterBrandSvg(): SafeHtml | null;
161
+ ngOnInit(): void;
162
+ ngAfterViewInit(): void;
163
+ ngOnDestroy(): void;
164
+ onWindowScroll(): void;
165
+ scrollToSection(target: string): void;
166
+ toggleMobileMenu(): void;
167
+ navigateTo(path: string): void;
168
+ iconBg(hex: string): string;
169
+ private applyColors;
170
+ static ɵfac: i0.ɵɵFactoryDeclaration<SpaLandingComponent, never>;
171
+ static ɵcmp: i0.ɵɵComponentDeclaration<SpaLandingComponent, "spa-landing", never, { "config": { "alias": "config"; "required": false; }; }, {}, never, ["[lpHeroVisual]", "[lpCustomSection]"], true, never>;
172
+ }
173
+
174
+ export { ALSQUARE_SVG_DARK, ALSQUARE_SVG_WHITE, SpaLandingComponent };
175
+ export type { LandingBrandOverride, LandingColors, LandingConfig, LandingFeature, LandingFooterColumn, LandingFooterLink, LandingMetric, LandingModuleGroup, LandingModuleTile, LandingNavLink, LandingPricingPlan, LandingSecurityItem, LandingStep, LandingTestimonial };
@@ -0,0 +1,141 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnInit, ChangeDetectorRef } from '@angular/core';
3
+ import * as i1 from '@angular/router';
4
+ import { Router, ActivatedRoute } from '@angular/router';
5
+ import * as i5 from '@angular/common';
6
+ import { Location } from '@angular/common';
7
+ import * as i6 from 'tin-spa/core';
8
+ import { DataServiceLib, AuthService, HttpService, StorageService, MessageService, LogService, NotificationsService, SignalRService, SetupService, LastRouteService, PreferencesService, TinSpaRuntimeConfig, ApiErrorService, User, AppConfig, SignupData, ApiResponse } from 'tin-spa/core';
9
+ import * as i7 from '@abacritt/angularx-social-login';
10
+ import { SocialAuthServiceConfig, SocialUser } from '@abacritt/angularx-social-login';
11
+ import { MsalService } from '@azure/msal-angular';
12
+ import { MatDialog } from '@angular/material/dialog';
13
+ import * as i4 from '@angular/forms';
14
+
15
+ declare class LoginRoutingModule {
16
+ static ɵfac: i0.ɵɵFactoryDeclaration<LoginRoutingModule, never>;
17
+ static ɵmod: i0.ɵɵNgModuleDeclaration<LoginRoutingModule, never, [typeof i1.RouterModule], [typeof i1.RouterModule]>;
18
+ static ɵinj: i0.ɵɵInjectorDeclaration<LoginRoutingModule>;
19
+ }
20
+
21
+ declare class LoginComponent implements OnInit {
22
+ private httpService;
23
+ private storageService;
24
+ router: Router;
25
+ private messageService;
26
+ dataService: DataServiceLib;
27
+ authService: AuthService;
28
+ private logService;
29
+ private route;
30
+ private notificationsService;
31
+ private signalRService;
32
+ private msalService;
33
+ private dialog;
34
+ private setupService;
35
+ private lastRouteService;
36
+ private preferencesService;
37
+ private runtimeConfig;
38
+ private apiErrorService;
39
+ private socialAuthConfig;
40
+ constructor(httpService: HttpService, storageService: StorageService, router: Router, messageService: MessageService, dataService: DataServiceLib, authService: AuthService, logService: LogService, route: ActivatedRoute, notificationsService: NotificationsService, signalRService: SignalRService, msalService: MsalService | null, dialog: MatDialog, // Changed: MsalService is now @Optional() — an app that never registers MSAL gets null here instead of a NullInjectorError; the Microsoft button hides itself (showMicrosoftAuth)
41
+ setupService: SetupService, lastRouteService: LastRouteService, preferencesService: PreferencesService, // Added (chunk C): the user's chosen landing page outranks the saved last route
42
+ runtimeConfig: TinSpaRuntimeConfig, apiErrorService: ApiErrorService, // Added: routes application-level (HTTP 200, success:false) failures through the shared classify + dedupe path
43
+ socialAuthConfig: SocialAuthServiceConfig | null);
44
+ private resumeTarget;
45
+ private resumeNavigate;
46
+ ngOnInit(): void;
47
+ get showMicrosoftAuth(): boolean;
48
+ loginWithMS(): void;
49
+ private doMsalLoginPopup;
50
+ autoLogin: boolean;
51
+ socialUser: SocialUser | null;
52
+ rememberMe: boolean;
53
+ style: string;
54
+ email: string;
55
+ password: string;
56
+ redirectPath: any;
57
+ user: User;
58
+ hide: boolean;
59
+ isProcessing: boolean;
60
+ restoring: boolean;
61
+ restoreOffline: boolean;
62
+ private manualLogin;
63
+ appConfig: AppConfig;
64
+ signup(): void;
65
+ recoverAccount(): void;
66
+ signInManually(): void;
67
+ private logSsoDiagnostics;
68
+ private setupForm;
69
+ login(): void;
70
+ notifications(): void;
71
+ openTerms(): void;
72
+ openPrivacy(): void;
73
+ static ɵfac: i0.ɵɵFactoryDeclaration<LoginComponent, [null, null, null, null, null, null, null, null, null, null, { optional: true; }, null, null, null, null, null, null, { optional: true; }]>;
74
+ static ɵcmp: i0.ɵɵComponentDeclaration<LoginComponent, "spa-login", never, {}, {}, never, never, false, never>;
75
+ }
76
+
77
+ declare class SignupComponent implements OnInit {
78
+ private httpService;
79
+ private messageService;
80
+ dataService: DataServiceLib;
81
+ authService: AuthService;
82
+ private storageService;
83
+ router: Router;
84
+ private msalService;
85
+ private notificationsService;
86
+ private setupService;
87
+ private dialog;
88
+ private cdr;
89
+ private apiErrorService;
90
+ constructor(httpService: HttpService, messageService: MessageService, dataService: DataServiceLib, authService: AuthService, storageService: StorageService, router: Router, msalService: MsalService | null, // Changed: @Optional() — an app that never registers MSAL gets null here instead of a NullInjectorError; the Microsoft button hides itself (showMicrosoftAuth)
91
+ notificationsService: NotificationsService, setupService: SetupService, // Added: SetupService for setup badge
92
+ dialog: MatDialog, cdr: ChangeDetectorRef, // Changed: Inject ChangeDetectorRef for invitation toggle
93
+ apiErrorService: ApiErrorService);
94
+ ngOnInit(): void;
95
+ appConfig: AppConfig;
96
+ style: string;
97
+ signupData: SignupData;
98
+ step: 'provider' | 'form' | 'invitations' | 'complete';
99
+ isProcessing: boolean;
100
+ handleProviderAuth(token: string, authType: string, userName: string): void;
101
+ get showMicrosoftAuth(): boolean;
102
+ loginWithMS(): void;
103
+ private doMsalLoginPopup;
104
+ toggleInvitation(invitation: any): void;
105
+ submit(): void;
106
+ completeLogin(apiResponse: ApiResponse): void;
107
+ goToDashboard(): void;
108
+ goToLogin(): void;
109
+ openTerms(): void;
110
+ openPrivacy(): void;
111
+ static ɵfac: i0.ɵɵFactoryDeclaration<SignupComponent, [null, null, null, null, null, null, { optional: true; }, null, null, null, null, null]>;
112
+ static ɵcmp: i0.ɵɵComponentDeclaration<SignupComponent, "spa-signup", never, {}, {}, never, never, false, never>;
113
+ }
114
+
115
+ declare class RecoverAccountComponent implements OnInit {
116
+ private location;
117
+ private dataService;
118
+ authService: AuthService;
119
+ private messageService;
120
+ private apiErrorService;
121
+ constructor(location: Location, dataService: DataServiceLib, authService: AuthService, messageService: MessageService, apiErrorService: ApiErrorService);
122
+ ngOnInit(): void;
123
+ userName: string;
124
+ recover(): void;
125
+ static ɵfac: i0.ɵɵFactoryDeclaration<RecoverAccountComponent, never>;
126
+ static ɵcmp: i0.ɵɵComponentDeclaration<RecoverAccountComponent, "spa-recover-account", never, {}, {}, never, never, false, never>;
127
+ }
128
+
129
+ declare class SpaIndexModule {
130
+ static ɵfac: i0.ɵɵFactoryDeclaration<SpaIndexModule, never>;
131
+ static ɵmod: i0.ɵɵNgModuleDeclaration<SpaIndexModule, [typeof LoginComponent, typeof SignupComponent, typeof RecoverAccountComponent], [typeof i4.ReactiveFormsModule, typeof i5.CommonModule, typeof i4.FormsModule, typeof i4.ReactiveFormsModule, typeof i6.SpaCoreModule, typeof i7.SocialLoginModule], [typeof i5.CommonModule, typeof i4.FormsModule, typeof i6.SpaCoreModule, typeof LoginComponent, typeof SignupComponent, typeof RecoverAccountComponent]>;
132
+ static ɵinj: i0.ɵɵInjectorDeclaration<SpaIndexModule>;
133
+ }
134
+
135
+ declare class LoginModule {
136
+ static ɵfac: i0.ɵɵFactoryDeclaration<LoginModule, never>;
137
+ static ɵmod: i0.ɵɵNgModuleDeclaration<LoginModule, never, [typeof i5.CommonModule, typeof LoginRoutingModule, typeof SpaIndexModule], never>;
138
+ static ɵinj: i0.ɵɵInjectorDeclaration<LoginModule>;
139
+ }
140
+
141
+ export { LoginComponent, LoginModule, LoginRoutingModule, RecoverAccountComponent, SignupComponent, SpaIndexModule };
package/map/index.d.ts ADDED
@@ -0,0 +1,148 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnChanges, OnDestroy, EventEmitter, ElementRef, NgZone, SimpleChanges } from '@angular/core';
3
+ import { Observable } from 'rxjs';
4
+ import { MatDialogRef, MatDialog } from '@angular/material/dialog';
5
+
6
+ declare class MapConfig {
7
+ position?: string | MapPoint | null;
8
+ title?: string;
9
+ subtitle?: string;
10
+ caption?: string;
11
+ zoom?: number;
12
+ mapTypeId?: MapTypeId;
13
+ showCoordinates?: boolean;
14
+ showMapTypeToggle?: boolean;
15
+ interactive?: boolean;
16
+ tileUrl?: string;
17
+ attribution?: string;
18
+ imageryTileUrl?: string;
19
+ imageryAttribution?: string;
20
+ apiKey?: string;
21
+ emptyMessage?: string;
22
+ emptyDetail?: string;
23
+ height?: string;
24
+ markers?: MapMarker[];
25
+ fitMarkers?: boolean;
26
+ fleetTitle?: string;
27
+ }
28
+ interface MapMarker {
29
+ id: string | number;
30
+ position: string | MapPoint | null | undefined;
31
+ title?: string;
32
+ subtitle?: string;
33
+ caption?: string;
34
+ heading?: number | null;
35
+ speed?: number | null;
36
+ speedUnit?: string;
37
+ at?: string | Date | null;
38
+ stale?: boolean;
39
+ }
40
+ interface MapPositionUpdate {
41
+ id: string | number;
42
+ position?: string | MapPoint | null;
43
+ lat?: number | null;
44
+ lng?: number | null;
45
+ at?: string | Date | null;
46
+ speed?: number | null;
47
+ heading?: number | null;
48
+ }
49
+ interface ResolvedMapMarker {
50
+ marker: MapMarker;
51
+ point: MapPoint;
52
+ key: string;
53
+ }
54
+ declare function normaliseMarkers(markers: MapMarker[] | null | undefined): ResolvedMapMarker[];
55
+ declare function markerKey(id: string | number | null | undefined): string | null;
56
+ declare function updatePoint(update: MapPositionUpdate | null | undefined): MapPoint | null;
57
+ interface MapPoint {
58
+ lat: number;
59
+ lng: number;
60
+ }
61
+ type MapTypeId = 'roadmap' | 'satellite' | 'hybrid' | 'terrain';
62
+ declare function parseMapPoint(value: string | MapPoint | null | undefined): MapPoint | null;
63
+ declare function formatMapPoint(point: MapPoint | null): string;
64
+
65
+ type MapState = 'loading' | 'ready' | 'empty' | 'unavailable';
66
+ declare class MapComponent implements OnChanges, OnDestroy {
67
+ private zone;
68
+ config: MapConfig;
69
+ positionStream: Observable<MapPositionUpdate> | null;
70
+ followSelected: boolean;
71
+ closed: EventEmitter<void>;
72
+ markerSelected: EventEmitter<MapMarker>;
73
+ markerMoved: EventEmitter<MapMarker>;
74
+ surface: ElementRef<HTMLDivElement>;
75
+ beacon: ElementRef<HTMLDivElement>;
76
+ state: MapState;
77
+ point: MapPoint | null;
78
+ coordinates: string;
79
+ mapType: MapTypeId;
80
+ offCentre: boolean;
81
+ fleet: boolean;
82
+ resolved: ResolvedMapMarker[];
83
+ selected: MapMarker | null;
84
+ selectedCoordinates: string;
85
+ dropped: number;
86
+ private map;
87
+ private marker;
88
+ private layers;
89
+ private streamSub;
90
+ private base;
91
+ private imagery;
92
+ private tilesSeen;
93
+ private settleTimer;
94
+ constructor(zone: NgZone);
95
+ get title(): string;
96
+ get subtitle(): string;
97
+ get caption(): string;
98
+ get showCoordinates(): boolean;
99
+ get emptyMessage(): string;
100
+ get emptyDetail(): string;
101
+ get fleetTitle(): string;
102
+ get reportingCount(): number;
103
+ get fleetSummary(): string;
104
+ get showMapTypeToggle(): boolean;
105
+ ngOnChanges(changes: SimpleChanges): void;
106
+ ngOnDestroy(): void;
107
+ refreshMarkers(): void;
108
+ private start;
109
+ private draw;
110
+ private watchTiles;
111
+ private attachBeacon;
112
+ private drawMarkers;
113
+ private addMarker;
114
+ private beaconHtml;
115
+ private applyMarkers;
116
+ private restyleMarker;
117
+ applyPositionUpdate(update: MapPositionUpdate | null | undefined): boolean;
118
+ markerPosition(id: string | number): MapPoint | null;
119
+ select(marker: MapMarker | null): void;
120
+ clearSelection(): void;
121
+ private fitToMarkers;
122
+ private dropLayers;
123
+ private subscribeStream;
124
+ setPosition(value: string | MapPoint | null | undefined, follow?: boolean): boolean;
125
+ recenter(): void;
126
+ zoomBy(delta: number): void;
127
+ toggleMapType(): void;
128
+ copyCoordinates(): void;
129
+ close(): void;
130
+ private teardown;
131
+ static ɵfac: i0.ɵɵFactoryDeclaration<MapComponent, never>;
132
+ static ɵcmp: i0.ɵɵComponentDeclaration<MapComponent, "spa-map", never, { "config": { "alias": "config"; "required": false; }; "positionStream": { "alias": "positionStream"; "required": false; }; "followSelected": { "alias": "followSelected"; "required": false; }; }, { "closed": "closed"; "markerSelected": "markerSelected"; "markerMoved": "markerMoved"; }, never, never, true, never>;
133
+ }
134
+
135
+ declare class MapDialogComponent {
136
+ dialogRef: MatDialogRef<MapDialogComponent>;
137
+ data: any;
138
+ config: MapConfig;
139
+ constructor(dialogRef: MatDialogRef<MapDialogComponent>, data: any);
140
+ close(): void;
141
+ static ɵfac: i0.ɵɵFactoryDeclaration<MapDialogComponent, never>;
142
+ static ɵcmp: i0.ɵɵComponentDeclaration<MapDialogComponent, "spa-map-dialog", never, {}, {}, never, never, true, never>;
143
+ }
144
+ declare function normaliseMapData(data: any): MapConfig;
145
+ declare function openMapDialog(dialog: MatDialog, data: MapConfig | string): MatDialogRef<MapDialogComponent, any>;
146
+
147
+ export { MapComponent, MapConfig, MapDialogComponent, formatMapPoint, markerKey, normaliseMapData, normaliseMarkers, openMapDialog, parseMapPoint, updatePoint };
148
+ export type { MapMarker, MapPoint, MapPositionUpdate, MapTypeId, ResolvedMapMarker };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tin-spa",
3
- "version": "20.14.99",
3
+ "version": "20.14.113",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/tnyagato/ng-space.git"
@@ -42,6 +42,30 @@
42
42
  ".": {
43
43
  "types": "./index.d.ts",
44
44
  "default": "./fesm2022/tin-spa.mjs"
45
+ },
46
+ "./core": {
47
+ "types": "./core/index.d.ts",
48
+ "default": "./fesm2022/tin-spa-core.mjs"
49
+ },
50
+ "./http": {
51
+ "types": "./http/index.d.ts",
52
+ "default": "./fesm2022/tin-spa-http.mjs"
53
+ },
54
+ "./keys": {
55
+ "types": "./keys/index.d.ts",
56
+ "default": "./fesm2022/tin-spa-keys.mjs"
57
+ },
58
+ "./landing": {
59
+ "types": "./landing/index.d.ts",
60
+ "default": "./fesm2022/tin-spa-landing.mjs"
61
+ },
62
+ "./login": {
63
+ "types": "./login/index.d.ts",
64
+ "default": "./fesm2022/tin-spa-login.mjs"
65
+ },
66
+ "./map": {
67
+ "types": "./map/index.d.ts",
68
+ "default": "./fesm2022/tin-spa-map.mjs"
45
69
  }
46
70
  },
47
71
  "sideEffects": false
@@ -384,6 +384,20 @@ table {
384
384
  .tin-grid-auto button {
385
385
  width: 100%;
386
386
  }
387
+
388
+ /* Added (A-0901-11, 2026-09-01): a blank field exists ONLY to reserve an empty CELL in the two-column
389
+ desktop grid. At this breakpoint .tin-grid is a single flex COLUMN, so there is no cell to hold open —
390
+ but the empty wrapper is still a flex item and still costs the full 0.5rem (8px) gap above, which is why
391
+ mobile dialogs showed a mystery double gap with no visible control in it. display:none removes it from
392
+ flex layout entirely; nothing short of that reclaims the gap (a zero-HEIGHT div still gets one, and
393
+ hiding the inner <label> leaves the wrapper behind).
394
+ 🔴 `:not(.span-col)` IS LOAD-BEARING — DO NOT SIMPLIFY IT AWAY. A blank that SPANS the row is a
395
+ deliberate vertical SPACER, not a grid filler: datalib.service.ts:1850 uses one as the top spacer of the
396
+ estate-wide Approval form, where it must keep working at every width. Only the non-spanning
397
+ cell-filler kind is meaningless here. blank-mobile-collapse.spec.ts pins both halves. */
398
+ .tin-grid > .tin-blank-field:not(.span-col) {
399
+ display: none;
400
+ }
387
401
  }
388
402
 
389
403
  .tin-cluster {
@@ -672,9 +686,12 @@ spa-form spa-check {
672
686
  padding-bottom: var(--tin-field-subscript-reserve);
673
687
  }
674
688
 
675
- /* Composite subfields share a row via flex, which defaults to align-items:stretch —
689
+ /* Composite subfields share a row, and a row layout defaults to align-items:stretch —
676
690
  a checkbox or label among boxed inputs would stretch instead of sitting on the
677
- band. Match the grid's top alignment so composites align by the same rule. */
691
+ band. Match the grid's top alignment so composites align by the same rule.
692
+ Changed (composite redesign, 2026-08-31): the row is now a CSS Grid rather than a
693
+ flex row (form.component.css) — `flex-start` is still the correct value for grid,
694
+ but the sizing rules that make the children divide the slot live with the component. */
678
695
  .composite-field-group {
679
696
  align-items: flex-start;
680
697
  }
@@ -908,6 +925,12 @@ spa-groups mat-chip .mat-icon {
908
925
  color: rgba(0, 0, 0, 0.55) !important; /* dimmed value text — still legible but clearly not editable */
909
926
  cursor: default;
910
927
  }
928
+ /* Added: a readonly textarea kept the browser's default resize gripper in its bottom-right corner — the one
929
+ affordance on the field that still looked draggable, promising an interaction the field does not offer.
930
+ Scoped to .spa-readonly, so an editable textarea keeps its gripper untouched. */
931
+ .mat-mdc-form-field.spa-readonly textarea.mat-mdc-input-element {
932
+ resize: none;
933
+ }
911
934
  .mat-mdc-form-field.spa-readonly .mat-mdc-floating-label,
912
935
  .mat-mdc-form-field.spa-readonly .mdc-floating-label {
913
936
  color: rgba(0, 0, 0, 0.38) !important; /* MDC disabled label color */
@@ -1582,3 +1605,59 @@ spa-groups mat-chip .mat-icon {
1582
1605
  --tin-grip-color-hover: rgba(144, 202, 249, 1);
1583
1606
  --tin-grip-disabled-color: rgba(176, 182, 192, 0.42);
1584
1607
  }
1608
+
1609
+ /* ------------------------------------------------------------------ A PAGE CLAIMING THE BOTTOM-RIGHT CORNER
1610
+ Added 2026-08-31. Library chrome is pinned to the bottom of the viewport and does not know what the page
1611
+ underneath it has put there.
1612
+
1613
+ The agent FAB is fixed bottom-right, which is also where a page may put its primary action — on the desktop
1614
+ POS till it sat on top of the full-bleed 88px CHARGE button. A page that owns that corner adds this class to
1615
+ <body> for as long as it is mounted (spa-pos does it in ngOnInit/ngOnDestroy), the same mechanism
1616
+ update.service.ts uses for `spa-update-prompt-open`. It must be on BODY, not on the page host: spa-agent is
1617
+ mounted by nav-menu, so it is not a descendant of the routed page and inherits nothing from it.
1618
+
1619
+ 104px = the 88px CHARGE button plus a 16px breathing gap, so the FAB clears the whole plinth button rather
1620
+ than resting on its edge.
1621
+
1622
+ 🔴 Changed 2026-08-31 (Arbiter B.1): lifting the FAB was the RIGHT fix on a PHONE and the WRONG one on a
1623
+ DESKTOP, and the difference is which way the till's primary action runs.
1624
+ On the phone presentation (spa-pos-compact) the CHARGE bar is full-bleed and IS the last 88px of the screen
1625
+ (pos-compact.component.css:204), so the collision is VERTICAL and 104px clears it.
1626
+ On the wide presentation the till is a two-column grid — catalogue plus a full-height TICKET RAIL down the
1627
+ right edge (pos-wide.component.css:85) — and CHARGE is the foot of that rail. Lifting the FAB by 104px moved
1628
+ it off the CHARGE button and straight onto the TOTAL, the single most-read value on a till. Every further
1629
+ pixel up lands on more of the rail: the rail is full-height, so there is NO vertical position on that column
1630
+ that is not somebody's content. THE COLLISION THERE IS HORIZONTAL, and so is the fix — the FAB moves LEFT of
1631
+ the rail and sits back down in its natural corner over the catalogue.
1632
+
1633
+ The widths are the rail's own, read from pos-wide.component.css, plus a 24px gutter:
1634
+ rail 380px (.pw-body grid-template-columns) -> 404px
1635
+ rail 320px (its own max-width:1100px block, same file:236) -> 344px
1636
+ The breakpoint is the library's existing 600px line — the same literal the POS shell swaps presentations on
1637
+ (pos.component.ts:68) and the same one agent.component.css:545 changes the FAB's own defaults at. No new
1638
+ breakpoint is introduced; 600.02px is just the exact complement of `max-width: 600px`.
1639
+
1640
+ 🔑 The vertical lift is now PHONE-ONLY, and on this library it is currently INERT: `showFab` stands the FAB
1641
+ DOWN below 600px because the bottom tab bar's Chat tab replaces it (agent.component.html:5-7), so no FAB
1642
+ exists at that width to collide with anything. It is kept, scoped, so that IF the FAB ever returns on the
1643
+ phone it clears the compact till's full-bleed 88px bar instead of sitting on it — but it no longer reaches
1644
+ the desktop, where it was doing the damage. */
1645
+ @media (max-width: 600px) {
1646
+ body.spa-page-owns-fab-corner {
1647
+ --tin-fab-bottom: 104px;
1648
+ }
1649
+ }
1650
+
1651
+ /* Above that line is the ONLY width where the FAB and the till actually coexist, and there the answer is
1652
+ purely horizontal: the FAB keeps its natural 24px bottom corner and steps left of the rail. */
1653
+ @media (min-width: 600.02px) {
1654
+ body.spa-page-owns-fab-corner {
1655
+ --tin-fab-right: 404px;
1656
+ }
1657
+ }
1658
+
1659
+ @media (min-width: 600.02px) and (max-width: 1100px) {
1660
+ body.spa-page-owns-fab-corner {
1661
+ --tin-fab-right: 344px;
1662
+ }
1663
+ }