@africanies/angular-web-sdk 0.1.8 → 0.1.10

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 (91) hide show
  1. package/.angular/cache/22.0.9/playground/.tsbuildinfo +1 -1
  2. package/.nx/cache/1149535958171016935/dist/libs/africanies-theme/README.md +46 -0
  3. package/.nx/cache/1149535958171016935/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +243 -0
  4. package/.nx/cache/1149535958171016935/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -0
  5. package/.nx/cache/1149535958171016935/dist/libs/africanies-theme/package.json +35 -0
  6. package/.nx/cache/1149535958171016935/dist/libs/africanies-theme/tailwind-preset.cjs +330 -0
  7. package/.nx/cache/1149535958171016935/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +178 -0
  8. package/.nx/cache/17289624717336768573/dist/libs/africanies-core/README.md +85 -0
  9. package/.nx/cache/17289624717336768573/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs +4639 -0
  10. package/.nx/cache/17289624717336768573/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs.map +1 -0
  11. package/.nx/cache/17289624717336768573/dist/libs/africanies-core/package.json +31 -0
  12. package/.nx/cache/17289624717336768573/dist/libs/africanies-core/types/africanies-africanies-core.d.ts +2748 -0
  13. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/README.md +68 -0
  14. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/assets/brand/africanies-logo-mini.png +0 -0
  15. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/assets/brand/africanies-logo.png +0 -0
  16. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/assets/brand/africanies-logo.svg +5 -0
  17. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/assets/carriers/dhl.svg +7 -0
  18. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +19998 -0
  19. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -0
  20. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/package.json +35 -0
  21. package/.nx/cache/3735952477975556635/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +5616 -0
  22. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/README.md +68 -0
  23. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/assets/brand/africanies-logo-mini.png +0 -0
  24. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/assets/brand/africanies-logo.png +0 -0
  25. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/assets/brand/africanies-logo.svg +5 -0
  26. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/assets/carriers/dhl.svg +7 -0
  27. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +19500 -0
  28. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -0
  29. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/package.json +35 -0
  30. package/.nx/cache/3953970051755345887/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +5521 -0
  31. package/.nx/cache/4225324930345532464/dist/libs/africanies-theme/README.md +46 -0
  32. package/.nx/cache/4225324930345532464/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +243 -0
  33. package/.nx/cache/4225324930345532464/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -0
  34. package/.nx/cache/4225324930345532464/dist/libs/africanies-theme/package.json +35 -0
  35. package/.nx/cache/4225324930345532464/dist/libs/africanies-theme/tailwind-preset.cjs +330 -0
  36. package/.nx/cache/4225324930345532464/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +176 -0
  37. package/.nx/cache/run.json +26 -26
  38. package/.nx/cache/terminalOutputs/1149535958171016935 +21 -0
  39. package/.nx/cache/terminalOutputs/12565224028063674529 +37 -0
  40. package/.nx/cache/terminalOutputs/13478445034325959094 +176 -0
  41. package/.nx/cache/terminalOutputs/15835338512221847842 +184 -182
  42. package/.nx/cache/terminalOutputs/17289624717336768573 +21 -0
  43. package/.nx/cache/terminalOutputs/17571479482482478257 +35 -0
  44. package/.nx/cache/terminalOutputs/3088264223473143358 +8 -0
  45. package/.nx/cache/terminalOutputs/3735952477975556635 +21 -0
  46. package/.nx/cache/terminalOutputs/3953970051755345887 +21 -0
  47. package/.nx/cache/terminalOutputs/4225324930345532464 +21 -0
  48. package/.nx/cache/terminalOutputs/4363587767476846758 +176 -0
  49. package/.nx/cache/terminalOutputs/8193462679279018087 +39 -0
  50. package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db +0 -0
  51. package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db-shm +0 -0
  52. package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db-wal +0 -0
  53. package/.nx/workspace-data/d/daemon.log +5890 -0
  54. package/.nx/workspace-data/d/server-process.json +2 -2
  55. package/.nx/workspace-data/file-map.json +3610 -3620
  56. package/.nx/workspace-data/nx_files.nxt +0 -0
  57. package/.nx/workspace-data/project-graph.json +2 -2
  58. package/apps/playground/src/app/pages/chip-page.ts +11 -1
  59. package/apps/playground/src/app/pages/tokens-page.ts +2 -2
  60. package/apps/playground/src/app/snippets/chip.snippets.ts +5 -0
  61. package/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs +6 -1
  62. package/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs.map +1 -1
  63. package/dist/libs/africanies-core/types/africanies-africanies-core.d.ts +6 -1
  64. package/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +8 -8
  65. package/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -1
  66. package/dist/libs/africanies-theme/tailwind-preset.cjs +3 -3
  67. package/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +5 -3
  68. package/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +848 -375
  69. package/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -1
  70. package/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +123 -30
  71. package/libs/africanies-core/src/index.ts +1 -1
  72. package/libs/africanies-core/src/lib/notification/notification-link.ts +6 -1
  73. package/libs/africanies-theme/src/lib/mode-color.safelist.ts +2 -2
  74. package/libs/africanies-theme/src/lib/mode-color.service.spec.ts +9 -7
  75. package/libs/africanies-theme/src/lib/mode-color.service.ts +9 -7
  76. package/libs/africanies-theme/tailwind-preset.cjs +3 -3
  77. package/libs/africanies-ui/src/lib/avatar/avatar-menu.component.ts +25 -21
  78. package/libs/africanies-ui/src/lib/button/button.component.spec.ts +13 -8
  79. package/libs/africanies-ui/src/lib/chip/chip.component.ts +74 -6
  80. package/libs/africanies-ui/src/lib/layout/app-shell-header.component.ts +39 -16
  81. package/libs/africanies-ui/src/lib/layout/header-greeting.util.ts +1 -1
  82. package/libs/africanies-ui/src/lib/layout/header-weather.spec.ts +87 -5
  83. package/libs/africanies-ui/src/lib/layout/header-weather.ts +35 -15
  84. package/libs/africanies-ui/src/lib/navigation/segment/segment.component.ts +98 -22
  85. package/libs/africanies-ui/src/lib/navigation/shipping-mode-switch/shipping-mode-switch.component.ts +193 -65
  86. package/libs/africanies-ui/src/lib/navigation/side-nav/africanies-side-nav.component.html +4 -2
  87. package/libs/africanies-ui/src/lib/navigation/side-nav/africanies-side-nav.component.ts +3 -1
  88. package/libs/africanies-ui/src/lib/table/table.component.spec.ts +3 -0
  89. package/libs/africanies-ui/src/lib/table/table.component.ts +197 -57
  90. package/package.json +1 -1
  91. package/tools/build-icon-sprite.mjs +1 -1
@@ -7,7 +7,7 @@ import { AsyncQueryStateModel, ModuleFilterConfigModel, FilterStateModel, Filter
7
7
  export { AsyncQueryStateModel, DEFAULT_FILTER_TRANSPORT, DEFAULT_PAGE_SIZE, FILTER_CONFIGS, FilterConfigId, FilterFieldModel, FilterFieldType, FilterOptionModel, FilterOptionsSource, FilterParamsModel, FilterQueryBag, FilterStateModel, FilterTransport, ModuleFilterConfigModel, NOTIFICATION_PAGE_SIZE, PAGINATION_PAGE_SIZES, PaginationMetaModel, PaginationPageSize, clearFilterField, cloneFilterState, emptyFilterState, filterQueryKeys, fromFilterParams, hasFilterParams, resetFilterState, resolveFilterTransport, shipmentTrackingItemFilterConfig, toFilterParams, trackShipmentsFilterConfig, updateShipmentsFilterConfig, usersFilterConfig } from '@africanies/africanies-models';
8
8
  import * as _africanies_africanies_theme from '@africanies/africanies-theme';
9
9
  import { ModeColorService } from '@africanies/africanies-theme';
10
- import { AfricaniesHttpToastHandler, OverlayHandle, OverlayOpener } from '@africanies/africanies-core';
10
+ import { AfricaniesHttpToastHandler, OverlayHandle, OverlayOpener, ShippingModeService } from '@africanies/africanies-core';
11
11
  import { Observable } from 'rxjs';
12
12
  import { ControlValueAccessor } from '@angular/forms';
13
13
  import * as _africanies_africanies_ui from '@africanies/africanies-ui';
@@ -654,14 +654,19 @@ declare class AlertComponent {
654
654
  /**
655
655
  * Semantic tone for {@link ChipComponent}.
656
656
  *
657
+ * Prefer these for common statuses. For one-off accents, pass {@link ChipComponent.color}
658
+ * instead — any CSS color with a faded background.
659
+ *
657
660
  * - `neutral` — generic label / count
658
661
  * - `success` — positive outcome (same green family as export)
659
662
  * - `warning` — caution / pending
660
663
  * - `danger` — error / exception
664
+ * - `info` — informational (theme blue)
665
+ * - `violet` / `teal` / `rose` / `cyan` — extra categorical tones
661
666
  * - `export` — SFN / outbound accent
662
667
  * - `import` — STN / inbound accent
663
668
  */
664
- type ChipVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'export' | 'import';
669
+ type ChipVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'violet' | 'teal' | 'rose' | 'cyan' | 'export' | 'import';
665
670
  /**
666
671
  * Control size for {@link ChipComponent}.
667
672
  */
@@ -670,18 +675,25 @@ type ChipSize = 'sm' | 'md';
670
675
  * Compact status / category label.
671
676
  *
672
677
  * Soft fills stay readable in dark mode (translucent accent tints, not
673
- * light-only subtle backgrounds).
678
+ * light-only subtle backgrounds). Pass {@link color} for a custom accent —
679
+ * text uses that color and the background is a faded mix of the same.
674
680
  *
675
681
  * @example
676
682
  * ```html
677
683
  * <africanies-chip variant="success">Delivered</africanies-chip>
678
- * <africanies-chip variant="import" icon="truck">In transit</africanies-chip>
684
+ * <africanies-chip variant="violet">Priority</africanies-chip>
685
+ * <africanies-chip color="#0f766e">Pay Later</africanies-chip>
679
686
  * <africanies-chip variant="warning" [removable]="true" (removed)="clear()">Pending</africanies-chip>
680
687
  * ```
681
688
  */
682
689
  declare class ChipComponent {
683
- /** Semantic tone. Defaults to `neutral`. */
690
+ /** Semantic tone. Defaults to `neutral`. Ignored when {@link color} is set. */
684
691
  readonly variant: _angular_core.InputSignal<ChipVariant>;
692
+ /**
693
+ * Optional CSS color (`#7c3aed`, `rgb(…)`, `oklch(…)`, …). When set, overrides
694
+ * {@link variant}: label uses the color and the fill is a faded mix of it.
695
+ */
696
+ readonly color: _angular_core.InputSignal<string | null>;
685
697
  /** Padding / type scale. Defaults to `sm` (table / dense UI). */
686
698
  readonly size: _angular_core.InputSignal<ChipSize>;
687
699
  /** Optional leading icon. */
@@ -696,11 +708,14 @@ declare class ChipComponent {
696
708
  /** Emitted when the remove control is activated. */
697
709
  readonly removed: _angular_core.OutputEmitterRef<void>;
698
710
  protected readonly iconSize: _angular_core.Signal<14 | 12>;
711
+ /** Trimmed custom accent, or `null` when using a named {@link variant}. */
712
+ protected readonly customAccent: _angular_core.Signal<string | null>;
699
713
  protected readonly hostClass: _angular_core.Signal<string>;
700
714
  /**
701
- * Soft background + text per variant. Dark mode uses translucent accents so
702
- * chips never wash out as near-white blobs.
703
- * @returns Tailwind class string for the active variant.
715
+ * Soft background + text per variant, or the custom-color host class.
716
+ * Dark mode uses translucent accents so chips never wash out as near-white
717
+ * blobs.
718
+ * @returns Tailwind / host class string for the active tone.
704
719
  */
705
720
  private toneClass;
706
721
  /**
@@ -708,7 +723,7 @@ declare class ChipComponent {
708
723
  */
709
724
  protected onRemove(event: Event): void;
710
725
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ChipComponent, never>;
711
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChipComponent, "africanies-chip", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; }, { "removed": "removed"; }, never, ["*"], true, never>;
726
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ChipComponent, "africanies-chip", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "removeLabel": { "alias": "removeLabel"; "required": false; "isSignal": true; }; }, { "removed": "removed"; }, never, ["*"], true, never>;
712
727
  }
713
728
 
714
729
  /** Known inbound / last-mile carrier slugs with bundled SVG marks. */
@@ -3603,7 +3618,9 @@ interface AfricaniesSideNavItem {
3603
3618
  * **Expanded rail:** branches start open by default (`expandBranchesByDefault`).
3604
3619
  * Clicking a parent only opens/closes the branch (no route change). When any
3605
3620
  * branch is open, a sticky collapse-all control sits above the list (top right).
3606
- * The rail expand/collapse control stays pinned in the logo header.
3621
+ * The rail expand/collapse control stays pinned in the logo header. Project
3622
+ * chrome above the scrollable list with `pre-nav` (e.g. shipping modes) or
3623
+ * below with `footer`.
3607
3624
  * **Collapsed rail:** clicking a parent expands the rail, opens the
3608
3625
  * branch, and activates the first enabled child (router or `activeId`).
3609
3626
  *
@@ -3718,7 +3735,7 @@ declare class SideNavComponent {
3718
3735
  private ensureAncestorsOpen;
3719
3736
  private findPath;
3720
3737
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SideNavComponent, never>;
3721
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SideNavComponent, "africanies-side-nav", never, { "items": { "alias": "items"; "required": true; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "activeId": { "alias": "activeId"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "expandParents": { "alias": "expandParents"; "required": false; "isSignal": true; }; "expandBranchesByDefault": { "alias": "expandBranchesByDefault"; "required": false; "isSignal": true; }; "linkActiveOptions": { "alias": "linkActiveOptions"; "required": false; "isSignal": true; }; "showLogo": { "alias": "showLogo"; "required": false; "isSignal": true; }; "logoSrc": { "alias": "logoSrc"; "required": false; "isSignal": true; }; "logoMiniSrc": { "alias": "logoMiniSrc"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; "activeId": "activeIdChange"; }, never, ["[brand]", "[footer]"], true, never>;
3738
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SideNavComponent, "africanies-side-nav", never, { "items": { "alias": "items"; "required": true; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "activeId": { "alias": "activeId"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "expandParents": { "alias": "expandParents"; "required": false; "isSignal": true; }; "expandBranchesByDefault": { "alias": "expandBranchesByDefault"; "required": false; "isSignal": true; }; "linkActiveOptions": { "alias": "linkActiveOptions"; "required": false; "isSignal": true; }; "showLogo": { "alias": "showLogo"; "required": false; "isSignal": true; }; "logoSrc": { "alias": "logoSrc"; "required": false; "isSignal": true; }; "logoMiniSrc": { "alias": "logoMiniSrc"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; "activeId": "activeIdChange"; }, never, ["[brand]", "[pre-nav]", "[footer]"], true, never>;
3722
3739
  }
3723
3740
 
3724
3741
  /** Router target for the app-shell header back control. */
@@ -3834,6 +3851,10 @@ declare function isNavItemActive(router: Router, item: NavRouteTarget, options:
3834
3851
  /**
3835
3852
  * Compact segmented control for view modes and filters.
3836
3853
  *
3854
+ * Selected option uses a **solid brand pill** (white label) on a neutral track —
3855
+ * same pattern as the portal shipping-mode toggle. With exactly two options the
3856
+ * pill slides; with more options each selected chip fills in place.
3857
+ *
3837
3858
  * ## Router mode (URL is source of truth)
3838
3859
  *
3839
3860
  * Set `routerLink` (and optional `queryParams`) on items. The selected pill
@@ -3879,12 +3900,37 @@ declare class SegmentComponent {
3879
3900
  */
3880
3901
  readonly keepScroll: _angular_core.InputSignalWithTransform<boolean, unknown>;
3881
3902
  private readonly url;
3882
- protected readonly segmentChrome: _angular_core.Signal<string>;
3883
- protected readonly selectedClass: _angular_core.Signal<string>;
3884
- protected readonly idleClass: _angular_core.Signal<string>;
3903
+ /** Two equal options → portal-style sliding brand pill. */
3904
+ protected readonly useSlidingThumb: _angular_core.Signal<boolean>;
3905
+ /** Index of the active option (0 / 1 for the sliding thumb). */
3906
+ protected readonly activeIndex: _angular_core.Signal<number>;
3885
3907
  constructor();
3886
3908
  protected hrefFor(item: AfricaniesNavItem): string | null;
3887
3909
  protected isItemActive(item: AfricaniesNavItem): boolean;
3910
+ /**
3911
+ * Sliding thumb fill. STN / SFN options keep their own brand color so the
3912
+ * pill matches mode identity; other pairs follow the active theme primary.
3913
+ */
3914
+ protected thumbFillClass(): string;
3915
+ /**
3916
+ * Option chrome: sliding mode keeps labels transparent over the thumb;
3917
+ * multi-option mode paints a solid selected chip in place.
3918
+ *
3919
+ * @param item - Option being rendered.
3920
+ * @returns Class string for the control.
3921
+ */
3922
+ protected optionChrome(item: AfricaniesNavItem): string;
3923
+ /**
3924
+ * Solid brand fill for a selected option / sliding thumb.
3925
+ *
3926
+ * Light + dark use the same SFN green / STN orange primaries so the control
3927
+ * stays mode-identifiable on both surfaces (portal primary, not soft tint).
3928
+ * Class strings are full literals so Tailwind keeps them.
3929
+ *
3930
+ * @param id - Option id (`stn` / `sfn` get fixed brands; else theme primary).
3931
+ * @returns Background utility classes.
3932
+ */
3933
+ protected brandFillFor(id: string | null): string;
3888
3934
  protected selectLocal(item: AfricaniesNavItem): void;
3889
3935
  /**
3890
3936
  * Primary click navigates in-app without scrolling to top. Modified clicks
@@ -3904,12 +3950,13 @@ declare class SegmentComponent {
3904
3950
  * import orange; **from Nigeria** uses export green. Both tiles keep equal
3905
3951
  * chrome so unselected does not look like floating text.
3906
3952
  *
3907
- * Project into `<africanies-side-nav>` with the `footer` attribute.
3953
+ * Project into `<africanies-side-nav>` with the `pre-nav` attribute (above the
3954
+ * nav list). `footer` still works for legacy placement under the list.
3908
3955
  *
3909
3956
  * @example
3910
3957
  * ```html
3911
3958
  * <africanies-side-nav [items]="nav" [(collapsed)]="collapsed">
3912
- * <africanies-shipping-mode-switch footer [collapsed]="collapsed()" />
3959
+ * <africanies-shipping-mode-switch pre-nav [collapsed]="collapsed()" />
3913
3960
  * </africanies-side-nav>
3914
3961
  * ```
3915
3962
  */
@@ -3928,10 +3975,20 @@ declare class ShippingModeSwitchComponent {
3928
3975
  * Icon-only stacked tiles when the side nav rail is collapsed.
3929
3976
  */
3930
3977
  readonly collapsed: _angular_core.InputSignalWithTransform<boolean, unknown>;
3978
+ /**
3979
+ * When true, the mode tiles are visible. Persisted in `localStorage`.
3980
+ * Two-way bindable for hosts that need to force-open (e.g. onboarding).
3981
+ */
3982
+ readonly panelOpen: _angular_core.ModelSignal<boolean>;
3931
3983
  /** Active mode from {@link ShippingModeService}. */
3932
3984
  protected readonly mode: _angular_core.Signal<ShippingMode>;
3933
- /** Host padding / divider — tighter when the rail is collapsed. */
3934
- protected readonly hostClass: _angular_core.Signal<"block shrink-0 border-t border-border px-1.5 py-3 dark:border-white/10" | "block shrink-0 border-t border-border px-2 py-3 dark:border-white/10">;
3985
+ protected readonly modeChipLabel: _angular_core.Signal<"STN" | "SFN">;
3986
+ protected readonly modeChipVariant: _angular_core.Signal<ChipVariant>;
3987
+ /** Host padding / divider — sits above the nav list (`border-b`). */
3988
+ protected readonly hostClass: _angular_core.Signal<"block shrink-0 border-b border-border px-1.5 py-2 dark:border-white/10" | "block shrink-0 border-b border-border px-2 py-2.5 dark:border-white/10">;
3989
+ constructor();
3990
+ /** Show or hide the mode tiles. */
3991
+ protected togglePanel(): void;
3935
3992
  /**
3936
3993
  * Requests a mode change through {@link ShippingModeService.requestModeChange}
3937
3994
  * so feature guards (e.g. Create Shipment confirm) can run first.
@@ -3950,7 +4007,7 @@ declare class ShippingModeSwitchComponent {
3950
4007
  */
3951
4008
  protected cardClass(option: ShippingMode): string;
3952
4009
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ShippingModeSwitchComponent, never>;
3953
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ShippingModeSwitchComponent, "africanies-shipping-mode-switch", never, { "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
4010
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ShippingModeSwitchComponent, "africanies-shipping-mode-switch", never, { "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "panelOpen": { "alias": "panelOpen"; "required": false; "isSignal": true; }; }, { "panelOpen": "panelOpenChange"; }, never, never, true, never>;
3954
4011
  }
3955
4012
 
3956
4013
  /**
@@ -4349,7 +4406,7 @@ interface HeaderWeather {
4349
4406
  kind: HeaderWeatherKind;
4350
4407
  /** Celsius, when the forecast includes it. */
4351
4408
  temperatureC?: number;
4352
- /** City from IP geolocation, when known. */
4409
+ /** City from reverse-geocode / IP geolocation, when known. */
4353
4410
  city?: string;
4354
4411
  }
4355
4412
  /**
@@ -4456,7 +4513,8 @@ declare class AppShellHeaderComponent {
4456
4513
  protected readonly greeting: _angular_core.Signal<_africanies_africanies_ui.HeaderGreeting | null>;
4457
4514
  protected readonly weatherIcon: _angular_core.Signal<"underline" | "info" | "warning" | "abacus" | "absolute-position" | "academy-cap" | "accessibility" | "accordion-menu" | "add-dock" | "adjust" | "adobe-flash" | "airplane" | "alarm" | "align-center" | "align-justify" | "align-left" | "align-right" | "alt-a" | "alt" | "ambulance" | "anchor" | "angle-double-down" | "angle-double-left" | "angle-double-right" | "angle-double-up" | "angle-down" | "angle-left" | "angle-right" | "angle-up" | "archive" | "archives" | "area-select" | "arrow-backward" | "arrow-circle-down-o" | "arrow-circle-down" | "arrow-circle-left-o" | "arrow-circle-left" | "arrow-circle-right-o" | "arrow-circle-right" | "arrow-circle-up-o" | "arrow-circle-up" | "arrow-down" | "arrow-forward" | "arrow-left" | "arrow-long-down" | "arrow-long-left" | "arrow-right" | "arrow-up" | "arrows-cross" | "arrows-long-h" | "arrows-long-right" | "arrows-long-up" | "arrows-long-v" | "arrows" | "asterisk" | "at" | "automation" | "backspace-a" | "backspace" | "backwards" | "ban" | "bar-chart-h" | "bar-chart-v" | "bar-chart" | "barcode" | "bed" | "bell-o" | "bell-slash-o" | "bell-slash" | "bell" | "boat" | "bold" | "bolt" | "bomb" | "book-dollar" | "book-percent" | "book" | "bookmark-o" | "bookmark" | "briefcase" | "browser" | "bug-o" | "bug" | "building-o" | "building" | "bullets" | "bullseye" | "bus" | "button" | "calc-book" | "calc" | "calendar-briefcase" | "calendar-clock" | "calendar-envelope" | "calendar-o" | "calendar-user" | "calendar" | "camera" | "car" | "caret-down" | "caret-left" | "caret-right" | "caret-square-down-o" | "caret-square-left-o" | "caret-square-right-o" | "caret-square-up-o" | "caret-up" | "cart-o" | "cart" | "cash" | "chart-3d" | "chart-grid" | "chart-line" | "chart-timeline" | "chart" | "chat" | "check-circle-o" | "check-circle" | "check-square-o" | "check-square" | "check" | "chevron-circle-down-o" | "chevron-circle-down" | "chevron-circle-left-o" | "chevron-circle-left" | "chevron-circle-right-o" | "chevron-circle-right" | "chevron-circle-up-o" | "chevron-circle-up" | "chevron-down-small" | "chevron-down" | "chevron-left-small" | "chevron-left" | "chevron-right-small" | "chevron-right" | "chevron-up-small" | "chevron-up" | "child" | "circle-thin" | "circle" | "clipboard-check" | "clipboard-cross" | "clipboard-heart" | "clipboard-pulse" | "clipboard-text" | "clipboard-user" | "clipboard" | "clock" | "close-big" | "close-circle-o" | "close-circle" | "close-small" | "close" | "cloud-download-o" | "cloud-download" | "cloud-o" | "cloud-upload-o" | "cloud-upload" | "cloud" | "cluster" | "code" | "coffee" | "cog-o" | "cog" | "cogs" | "coin-piles" | "coins" | "combobox" | "comment-ellipsis-o" | "comment-ellipsis" | "comment-o" | "comment" | "comments-o" | "comments" | "compile" | "compress-square" | "compress" | "connect-o" | "connect" | "controller" | "copy-o" | "copy" | "copyright" | "corner-lower-left" | "corner-lower-right" | "corner-upper-left" | "corner-upper-right" | "credit-card" | "crop" | "cross-cutlery" | "crosshairs" | "css" | "ctrl-a" | "ctrl" | "cube" | "cubes" | "curly-brackets" | "cursor-o" | "cursor" | "cutlery" | "dashboard" | "database" | "date-input" | "deindent" | "del-a" | "del" | "dental-chair" | "desktop" | "diamond-o" | "diamond" | "diasporan-partner" | "diploma-scroll" | "diploma" | "disc" | "doctor-briefcase" | "doctor" | "dollar" | "dot-circle" | "download-alt" | "download" | "drop" | "edit" | "eject" | "elastic" | "ellipsis-circle-o" | "ellipsis-circle" | "ellipsis-dots-h" | "ellipsis-dots-v" | "ellipsis-h" | "ellipsis-v" | "enter-arrow" | "enter" | "envelope-o" | "envelope-open-o" | "envelope-open" | "envelope" | "envelopes-o" | "envelopes" | "eraser" | "esc-a" | "esc" | "euro" | "exchange" | "exclamation-circle-o" | "exclamation-circle" | "exclamation" | "exit-o" | "exit" | "expand-full" | "expand-square" | "expand" | "external-browser" | "external-link" | "eye-slash" | "eye" | "eyedropper" | "facebook-square" | "facebook" | "factory" | "family" | "fast-backward" | "fast-forward" | "female" | "file-add" | "file-code" | "file-font" | "file-movie" | "file-o" | "file-picture" | "file-presentation" | "file-process" | "file-refresh" | "file-remove" | "file-search" | "file-sound" | "file-start" | "file-table" | "file-text-o" | "file-text" | "file-tree-small" | "file-tree-sub" | "file-tree" | "file-zip" | "file" | "fill" | "film" | "filter" | "fire" | "flag-checkered" | "flag-o" | "flag" | "flash" | "flask" | "flight-landing" | "flight-takeoff" | "flip-h" | "flip-v" | "folder-add" | "folder-o" | "folder-open-o" | "folder-open" | "folder-remove" | "folder-search" | "folder" | "font" | "form" | "forward" | "frown-o" | "funcion" | "funnel" | "gamepad" | "gavel" | "gift" | "glass" | "glasses" | "globe-wire" | "globe" | "golf" | "google-plus-square" | "google-plus" | "grab" | "grid-bevel" | "grid-big-o" | "grid-big" | "grid-h" | "grid-small-o" | "grid-small" | "grid-v" | "grid" | "group" | "hammer" | "hand-coins" | "hand" | "handle-corner" | "hands-up" | "handshake" | "harddrive-o" | "harddrive" | "hash" | "header" | "headphones" | "headset" | "health-card" | "heart-o" | "heart" | "home-o" | "home" | "hospital" | "hourglass-empty" | "hourglass-end" | "hourglass-start" | "hourglass" | "inbox" | "indent" | "info-circle-o" | "info-circle" | "input" | "insert" | "institution" | "invoice" | "italic" | "key-o" | "key" | "keyboard-o" | "keyboard" | "laptop" | "layout" | "level-down-bold" | "level-down" | "level-left-bold" | "level-left" | "level-right-bold" | "level-right" | "level-up-bold" | "level-up" | "lifebuoy" | "lightbulb" | "line-bar-chart" | "line-chart" | "line-h" | "line-v" | "lines-list" | "lines" | "link" | "list-ol" | "list-select" | "list-ul" | "list" | "location-arrow-circle-o" | "location-arrow-circle" | "location-arrow" | "lock" | "magic" | "magnet" | "mailbox" | "male" | "map-marker" | "margin-bottom" | "margin-left" | "margin-right" | "margin-top" | "margin" | "medal" | "megaphone" | "meh-o" | "menu" | "microphone" | "mini-partner" | "minus-circle-o" | "minus-circle" | "minus-square-o" | "minus" | "mobile-browser" | "mobile-retro" | "mobile" | "modal-list" | "modal" | "money-deposit" | "money-exchange" | "money-withdraw" | "money" | "moon-o" | "moon" | "morning" | "movie" | "music" | "mute" | "native-button" | "newspaper" | "notebook" | "number-count" | "nurse" | "office" | "open-book" | "option-a" | "option" | "options" | "orientation" | "out" | "outbox" | "package" | "padding-bottom" | "padding-left" | "padding-right" | "padding-top" | "padding" | "paint-roll" | "paintbrush" | "palette" | "panel" | "paperclip" | "paperplane-o" | "paperplane" | "paragraph" | "partner" | "password" | "paste" | "pause" | "pencil" | "phone-landline" | "phone" | "picture" | "pie-bar-chart" | "pie-chart" | "piggy-bank-coin" | "piggy-bank" | "pill" | "pills" | "pin-post" | "pin" | "play-circle-o" | "play-circle" | "play" | "plug" | "plus-circle-o" | "plus-circle" | "plus-minus" | "plus-square-o" | "plus" | "pointer" | "power-off" | "presentation" | "print" | "progressbar" | "puzzle-piece" | "pyramid-chart" | "qrcode" | "question-circle-o" | "question-circle" | "question" | "quote-left" | "quote-right" | "random" | "raster-lower-left" | "raster" | "records" | "recycle" | "refresh" | "reply-all" | "reply" | "resize-h" | "resize-v" | "retweet" | "rhombus" | "road-branch" | "road-branches" | "road-split" | "road" | "rocket" | "rotate-left" | "rotate-right" | "rss-square" | "rss" | "safe-lock" | "safe" | "scale-unbalance" | "scale" | "scatter-chart" | "scissors" | "screwdriver" | "search-minus" | "search-plus" | "search" | "select" | "server" | "share-square" | "share" | "shield" | "shift-arrow" | "shift" | "shop" | "sign-in-alt" | "sign-in" | "sign-out-alt" | "sign-out" | "signal" | "sitemap" | "slider" | "sliders" | "smiley-o" | "sort" | "sound-disable" | "spark-line" | "specialist" | "spinner-arc" | "spinner-third" | "spinner" | "spline-area-chart" | "spline-chart" | "split-h" | "split-v" | "split" | "spoon" | "square-shadow" | "star-half-left-o" | "star-half-left" | "star-half-right-o" | "star-half-right" | "star-o" | "star" | "start-cog" | "step-backward" | "step-forward" | "stethoscope" | "stock" | "stop-cog" | "stop" | "stopwatch" | "storage" | "strikethrough" | "subscript" | "suitcase" | "sun-down" | "sun-o" | "sun-rise" | "superscript" | "sword" | "tab-a" | "tab" | "table" | "tablet" | "tabs" | "tag" | "tags" | "tasks" | "taxi" | "teeth" | "terminal" | "text-height" | "text-input" | "text-label" | "text-width" | "thin-square" | "thumbs-down-o" | "thumbs-down" | "thumbs-up-o" | "thumbs-up" | "ticket" | "time-backward" | "time-forward" | "timer" | "toolbox" | "tools" | "tooth" | "touch" | "train" | "trash" | "tree-table" | "trending-down" | "trending-up" | "trophy" | "truck" | "twin-col-select" | "twitter-square" | "twitter" | "umbrella" | "unlink" | "unlock" | "upload-alt" | "upload" | "user-card" | "user-check" | "user-clock" | "user-heart" | "user-star" | "user" | "users" | "vaadin-h" | "vaadin-v" | "viewport" | "vimeo-square" | "vimeo" | "volume-down" | "volume-off" | "volume-up" | "volume" | "wallet" | "warehouse" | "workplace" | "wrench" | "youtube-square" | "youtube">;
4458
4515
  protected readonly weatherTemp: _angular_core.Signal<string | null>;
4459
- protected readonly weatherPlace: _angular_core.Signal<string>;
4516
+ protected readonly weatherCondition: _angular_core.Signal<string>;
4517
+ protected readonly weatherCity: _angular_core.Signal<string | null>;
4460
4518
  protected readonly weatherAriaLabel: _angular_core.Signal<string>;
4461
4519
  protected readonly unreadCount: _angular_core.Signal<number>;
4462
4520
  protected readonly unreadBadge: _angular_core.Signal<string>;
@@ -4805,8 +4863,10 @@ interface TableSortChange {
4805
4863
  * `<ng-template africaniesCellDef="key">` templates. Columns without a matching
4806
4864
  * template fall back to rendering `row[key]` as plain text.
4807
4865
  *
4808
- * Optional toolbar: top-left **Refresh** (`showRefresh` {@link refreshClick}).
4809
- * Hidden while the body shows empty or error — those states expose Retry instead.
4866
+ * Optional toolbar: top-left **shipping mode** segment (on by default;
4867
+ * `[showShippingMode]="false"` to hide) and **Refresh** (`showRefresh`
4868
+ * {@link refreshClick}). Refresh is hidden while
4869
+ * the body shows empty or error — those states expose Retry instead.
4810
4870
  * While {@link refreshing} is true the rows stay on screen — the refresh icon
4811
4871
  * spins (do not swap to a blocking loader). Use {@link loading} when the page
4812
4872
  * of data is changing (pagination / size): rows stay on screen, a keep-rows
@@ -4835,8 +4895,9 @@ interface TableSortChange {
4835
4895
  * and never reorder local rows.
4836
4896
  *
4837
4897
  * **Expandable rows:** project `<ng-template africaniesRowDetail="Label" let-row>`
4838
- * templates. A leading chevron column appears; the expanded panel renders each
4839
- * label with its template value in a responsive grid.
4898
+ * templates. A leading chevron column appears; the expanded panel sticks to the
4899
+ * scrollport width (so it does not scroll horizontally with the columns) and
4900
+ * lays out label/value pairs in a wrapping auto-fill grid.
4840
4901
  *
4841
4902
  * @typeParam T - Row record shape.
4842
4903
  *
@@ -4879,7 +4940,24 @@ interface TableSortChange {
4879
4940
  * page scroll is unchanged.
4880
4941
  */
4881
4942
  declare class TableComponent<T = unknown> {
4882
- protected readonly modeColor: ModeColorService;
4943
+ private readonly destroyRef;
4944
+ protected readonly shipping: ShippingModeService;
4945
+ /** Local STN / SFN segment options for {@link showShippingMode}. */
4946
+ protected readonly shippingModeItems: AfricaniesNavItem[];
4947
+ /**
4948
+ * Segment selection mirror of {@link ShippingModeService.mode}. Kept local
4949
+ * so a denied {@link ShippingModeService.requestModeChange} can snap the
4950
+ * pills back when the service mode did not change.
4951
+ */
4952
+ protected readonly shippingModeActiveId: _angular_core.WritableSignal<string>;
4953
+ /** Scrollport that owns horizontal overflow for the main grid. */
4954
+ private readonly scrollport;
4955
+ /**
4956
+ * Visible width of {@link scrollport}. Applied to the expand panel so
4957
+ * details stay within the viewport and do not scroll with the columns.
4958
+ */
4959
+ protected readonly scrollportWidthPx: _angular_core.WritableSignal<number>;
4960
+ constructor();
4883
4961
  /**
4884
4962
  * When false, hides row expansion even if {@link RowDetailDefDirective}
4885
4963
  * templates are projected. Defaults to true.
@@ -4913,6 +4991,13 @@ declare class TableComponent<T = unknown> {
4913
4991
  * server-side `order` param. Omitted / null means no column is active.
4914
4992
  */
4915
4993
  readonly sort: _angular_core.InputSignal<TableSortChange | null>;
4994
+ /**
4995
+ * Show the Shipping to / from Nigeria segment above the table (top-left).
4996
+ * On by default; set `[showShippingMode]="false"` to hide (e.g. modals).
4997
+ * Writes through {@link ShippingModeService.requestModeChange} so feature
4998
+ * guards still run.
4999
+ */
5000
+ readonly showShippingMode: _angular_core.InputSignalWithTransform<boolean, unknown>;
4916
5001
  /**
4917
5002
  * Show a Refresh button above the table (top-left) once rows are on screen.
4918
5003
  * Hidden during in-grid empty/error — those use Retry in the body. Host refetches
@@ -5004,10 +5089,17 @@ declare class TableComponent<T = unknown> {
5004
5089
  protected readonly colSpan: _angular_core.Signal<number>;
5005
5090
  protected readonly errorMessage: _angular_core.Signal<string>;
5006
5091
  protected readonly staleError: _angular_core.Signal<string | null>;
5007
- protected readonly bodyKind: _angular_core.Signal<"error" | "rows" | "loading" | "empty">;
5092
+ protected readonly bodyKind: _angular_core.Signal<"loading" | "error" | "empty" | "rows">;
5008
5093
  protected readonly paginationLoading: _angular_core.Signal<boolean>;
5009
5094
  /** Top-left Refresh — only when rows are on screen (empty/error use in-body Retry). */
5010
5095
  protected readonly showToolbarRefresh: _angular_core.Signal<boolean>;
5096
+ /**
5097
+ * Applies a shipping-mode segment selection through
5098
+ * {@link ShippingModeService.requestModeChange}.
5099
+ *
5100
+ * @param id - Segment id (`stn` / `sfn`) or null.
5101
+ */
5102
+ protected onShippingModeChange(id: string | null): void;
5011
5103
  protected readonly visibleRowIds: _angular_core.Signal<string[]>;
5012
5104
  protected readonly someRowsExpanded: _angular_core.Signal<boolean>;
5013
5105
  /** Lookup map rebuilt when projected cell defs change. */
@@ -5042,8 +5134,9 @@ declare class TableComponent<T = unknown> {
5042
5134
  */
5043
5135
  protected headerRowClass(): string;
5044
5136
  /**
5045
- * Opaque mode soft fill for header cells (sticky-safe in dark mode).
5046
- * @returns Soft solid background utilities.
5137
+ * Opaque header fill (sticky-safe). Neutral chrome — not mode-accented.
5138
+ * Light `#f0f2f5` / dark elevated ink surface.
5139
+ * @returns Background utility classes.
5047
5140
  */
5048
5141
  protected headerSoftClass(): string;
5049
5142
  /**
@@ -5161,7 +5254,7 @@ declare class TableComponent<T = unknown> {
5161
5254
  */
5162
5255
  protected onSortHeaderClick(key: string): void;
5163
5256
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TableComponent<any>, never>;
5164
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableComponent<any>, "africanies-table", never, { "expandable": { "alias": "expandable"; "required": false; "isSignal": true; }; "rowTrackBy": { "alias": "rowTrackBy"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "stickyHeader": { "alias": "stickyHeader"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "showRefresh": { "alias": "showRefresh"; "required": false; "isSignal": true; }; "refreshLabel": { "alias": "refreshLabel"; "required": false; "isSignal": true; }; "refreshing": { "alias": "refreshing"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "loadingLabel": { "alias": "loadingLabel"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "showFilter": { "alias": "showFilter"; "required": false; "isSignal": true; }; "filterLabel": { "alias": "filterLabel"; "required": false; "isSignal": true; }; "filterCount": { "alias": "filterCount"; "required": false; "isSignal": true; }; "showExport": { "alias": "showExport"; "required": false; "isSignal": true; }; "exportLabel": { "alias": "exportLabel"; "required": false; "isSignal": true; }; "meta": { "alias": "meta"; "required": false; "isSignal": true; }; }, { "rowExpandChange": "rowExpandChange"; "sortChange": "sortChange"; "refreshClick": "refreshClick"; "filterClick": "filterClick"; "exportClick": "exportClick"; "pageChange": "pageChange"; "sizeChange": "sizeChange"; }, ["cellDefs", "headerCellDefs", "rowDetailDefs"], never, true, never>;
5257
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TableComponent<any>, "africanies-table", never, { "expandable": { "alias": "expandable"; "required": false; "isSignal": true; }; "rowTrackBy": { "alias": "rowTrackBy"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "stickyHeader": { "alias": "stickyHeader"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": true; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "showShippingMode": { "alias": "showShippingMode"; "required": false; "isSignal": true; }; "showRefresh": { "alias": "showRefresh"; "required": false; "isSignal": true; }; "refreshLabel": { "alias": "refreshLabel"; "required": false; "isSignal": true; }; "refreshing": { "alias": "refreshing"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "loadingLabel": { "alias": "loadingLabel"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "showFilter": { "alias": "showFilter"; "required": false; "isSignal": true; }; "filterLabel": { "alias": "filterLabel"; "required": false; "isSignal": true; }; "filterCount": { "alias": "filterCount"; "required": false; "isSignal": true; }; "showExport": { "alias": "showExport"; "required": false; "isSignal": true; }; "exportLabel": { "alias": "exportLabel"; "required": false; "isSignal": true; }; "meta": { "alias": "meta"; "required": false; "isSignal": true; }; }, { "rowExpandChange": "rowExpandChange"; "sortChange": "sortChange"; "refreshClick": "refreshClick"; "filterClick": "filterClick"; "exportClick": "exportClick"; "pageChange": "pageChange"; "sizeChange": "sizeChange"; }, ["cellDefs", "headerCellDefs", "rowDetailDefs"], never, true, never>;
5165
5258
  }
5166
5259
 
5167
5260
  /** Page number or a gap marker for windowed pagination. */
@@ -210,9 +210,9 @@ export {
210
210
 
211
211
  // User notifications (auth required)
212
212
  export {
213
+ isNotificationExternalLink,
213
214
  mapNotification,
214
215
  mapNotificationInboxItem,
215
- isNotificationExternalLink,
216
216
  mapNotificationList,
217
217
  mapNotificationPayload,
218
218
  NOTIFICATION_READ_PATH,
@@ -12,7 +12,10 @@ const QUERY_SHIPMENT_APP = 'shipment_app';
12
12
  const LEGACY_PORTAL_HOST =
13
13
  /^(?:test-)?(?:admin|customer)-(?:export|import)\.africaniestest\.com$/i;
14
14
 
15
- /** Signed export downloads and other hosts that must not be rewritten in-app. */
15
+ /**
16
+ * Signed export downloads and other hosts that must not be rewritten in-app.
17
+ * @param link
18
+ */
16
19
  export function isNotificationExternalLink(link: string): boolean {
17
20
  const trimmed = decodeNotificationLink(link).trim();
18
21
  if (!trimmed) {
@@ -39,6 +42,8 @@ export function isNotificationExternalLink(link: string): boolean {
39
42
  * - Legacy portal hosts become relative `/portal/...` paths with query preserved.
40
43
  * - When the notification already includes `shipment_app`, it is kept as-is.
41
44
  * - Otherwise classic host / `shipment_app` rewriting applies for portal URLs.
45
+ * @param link
46
+ * @param mode
42
47
  */
43
48
  export function resolveNotificationLinkForMode(
44
49
  link: string | null | undefined,
@@ -12,7 +12,7 @@
12
12
  * text-export-strong bg-export-strong hover:bg-export-hover border-export-strong
13
13
  * text-export bg-export bg-export-subtle bg-export-light border-export
14
14
  * hover:bg-export-light hover:bg-export-subtle dark:bg-export/15 dark:hover:bg-export/15
15
- * dark:bg-[color-mix(in_srgb,#1cbd5d_15%,#212529)] dark:bg-export dark:text-export dark:border-export
15
+ * dark:bg-[color-mix(in_srgb,#26bd5d_15%,#212529)] dark:bg-export dark:text-export dark:border-export
16
16
  *
17
17
  * STN (import / orange):
18
18
  * text-import-strong bg-import-strong hover:bg-import-hover border-import-strong
@@ -35,7 +35,7 @@ export const MODE_COLOR_SAFELIST = [
35
35
  'dark:bg-export/15',
36
36
  'dark:hover:bg-export/15',
37
37
  'dark:hover:bg-export-light',
38
- 'dark:bg-[color-mix(in_srgb,#1cbd5d_15%,#212529)]',
38
+ 'dark:bg-[color-mix(in_srgb,#26bd5d_15%,#212529)]',
39
39
  'dark:bg-export',
40
40
  'dark:text-export',
41
41
  'dark:border-export',
@@ -26,14 +26,16 @@ describe('ModeColorService', () => {
26
26
  service = TestBed.inject(ModeColorService);
27
27
  });
28
28
 
29
- it('uses accessible export-strong fills and text in SFN light mode', () => {
29
+ it('uses export brand fills and text for SFN in light and dark', () => {
30
30
  const classes = service.classes();
31
- expect(classes.text).toContain('text-export-strong');
32
- expect(classes.primary).toContain('bg-export-strong');
33
- expect(classes.ghostPrimary).toContain('text-export-strong');
34
- expect(classes.activeFill).toContain('bg-export-strong');
35
- expect(classes.stroked).toContain('text-export-strong');
36
- expect(classes.stroked).toContain('border-export-strong');
31
+ const primaryTokens = classes.primary.split(/\s+/);
32
+ expect(classes.text.split(/\s+/)).toContain('text-export');
33
+ expect(primaryTokens).toContain('bg-export');
34
+ expect(primaryTokens).not.toContain('bg-export-strong');
35
+ expect(classes.ghostPrimary.split(/\s+/)).toContain('text-export');
36
+ expect(classes.activeFill.split(/\s+/)).toContain('bg-export');
37
+ expect(classes.stroked.split(/\s+/)).toContain('text-export');
38
+ expect(classes.stroked.split(/\s+/)).toContain('border-export');
37
39
  });
38
40
 
39
41
  it('keeps bright export accents for dark-mode companions in SFN', () => {
@@ -9,7 +9,9 @@ import { ShippingModeService } from '@africanies/africanies-core';
9
9
  * and accent text. Semantic colors (danger / warning) stay mode-independent.
10
10
  */
11
11
  export interface ModeColorClasses {
12
- /** Accessible accent text — `text-export-strong` in light, `text-export` in dark. */
12
+ /**
13
+ * Accessible accent text — mode brand color in light and dark.
14
+ */
13
15
  text: string;
14
16
  /** Solid background utility, e.g. `bg-export`. */
15
17
  bg: string;
@@ -80,22 +82,22 @@ export class ModeColorService {
80
82
  // Literal strings required for Tailwind content detection — do not interpolate.
81
83
  if (this.shippingMode.mode() === 'sfn') {
82
84
  return {
83
- text: 'text-export-strong dark:text-export',
85
+ text: 'text-export dark:text-export',
84
86
  bg: 'bg-export',
85
87
  bgSubtle: 'bg-export-subtle',
86
88
  border: 'border-export',
87
89
  primary:
88
- 'bg-export-strong text-white border-transparent hover:bg-export-hover dark:bg-export dark:hover:bg-export-light',
90
+ 'bg-export text-white border-transparent hover:bg-export-strong dark:bg-export dark:hover:bg-export-light',
89
91
  ghostPrimary:
90
- 'bg-transparent text-export-strong border-transparent hover:bg-export-subtle dark:text-export dark:hover:bg-export/15',
92
+ 'bg-transparent text-export border-transparent hover:bg-export-subtle dark:text-export dark:hover:bg-export/15',
91
93
  soft: 'bg-export-subtle dark:bg-export/15',
92
94
  softSolid:
93
- 'bg-export-subtle dark:bg-[color-mix(in_srgb,#1cbd5d_15%,#212529)]',
95
+ 'bg-export-subtle dark:bg-[color-mix(in_srgb,#26bd5d_15%,#212529)]',
94
96
  softHover: 'hover:bg-export-subtle dark:hover:bg-export/15',
95
97
  activeFill:
96
- 'bg-export-strong text-white border-transparent hover:bg-export-hover dark:bg-export dark:text-white dark:hover:bg-export-light',
98
+ 'bg-export text-white border-transparent hover:bg-export-strong dark:bg-export dark:text-white dark:hover:bg-export-light',
97
99
  stroked:
98
- 'bg-surface text-export-strong border-export-strong hover:bg-export-subtle dark:bg-ink-950 dark:text-export dark:border-export dark:hover:bg-export/15',
100
+ 'bg-surface text-export border-export hover:bg-export-subtle dark:bg-ink-950 dark:text-export dark:border-export dark:hover:bg-export/15',
99
101
  };
100
102
  }
101
103
  return {
@@ -270,7 +270,7 @@ module.exports = {
270
270
  hover: '#e9eef5',
271
271
  },
272
272
  export: {
273
- DEFAULT: '#1cbd5d',
273
+ DEFAULT: '#26bd5d',
274
274
  light: '#24dc6d',
275
275
  subtle: '#e4fff3',
276
276
  tint: '#f2fff8',
@@ -282,8 +282,8 @@ module.exports = {
282
282
  DEFAULT: '#f08829',
283
283
  light: '#ffa95b',
284
284
  subtle: '#fffcef',
285
- // Accessible normal-text / white-text-control foreground (6.20:1).
286
- strong: '#9a4b0b',
285
+ // Brand orange (same as DEFAULT) — portal STN primary.
286
+ strong: '#f08829',
287
287
  hover: '#7f3e09',
288
288
  },
289
289
  danger: {
@@ -37,28 +37,32 @@ import { AvatarComponent, type AvatarSize } from './avatar.component';
37
37
  AfricaniesIconComponent,
38
38
  ],
39
39
  template: `
40
- <africanies-action-menu
41
- [items]="menuItems()"
42
- [ariaLabel]="ariaLabel()"
43
- [disabled]="disabled()"
44
- >
45
- <button
46
- type="button"
47
- africaniesActionMenuTrigger
48
- class="inline-flex cursor-pointer items-center gap-1 rounded-lg p-0.5 pr-1 transition-colors hover:bg-background-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-white/10"
49
- [attr.aria-label]="ariaLabel()"
40
+ @if (menuItems().length > 0) {
41
+ <africanies-action-menu
42
+ [items]="menuItems()"
43
+ [ariaLabel]="ariaLabel()"
44
+ [disabled]="disabled()"
50
45
  >
51
- <africanies-avatar [name]="name()" [src]="src()" [size]="size()" />
52
- @if (showCaret()) {
53
- <africanies-icon
54
- name="chevron-down"
55
- [size]="14"
56
- class="shrink-0 text-neutral-600 dark:text-neutral-400"
57
- aria-hidden="true"
58
- />
59
- }
60
- </button>
61
- </africanies-action-menu>
46
+ <button
47
+ type="button"
48
+ africaniesActionMenuTrigger
49
+ class="inline-flex cursor-pointer items-center gap-1 rounded-lg p-0.5 pr-1 transition-colors hover:bg-background-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus disabled:cursor-not-allowed disabled:opacity-50 dark:hover:bg-white/10"
50
+ [attr.aria-label]="ariaLabel()"
51
+ >
52
+ <africanies-avatar [name]="name()" [src]="src()" [size]="size()" />
53
+ @if (showCaret()) {
54
+ <africanies-icon
55
+ name="chevron-down"
56
+ [size]="14"
57
+ class="shrink-0 text-neutral-600 dark:text-neutral-400"
58
+ aria-hidden="true"
59
+ />
60
+ }
61
+ </button>
62
+ </africanies-action-menu>
63
+ } @else {
64
+ <africanies-avatar [name]="name()" [src]="src()" [size]="size()" />
65
+ }
62
66
  `,
63
67
  })
64
68
  export class AvatarMenuComponent {
@@ -65,29 +65,34 @@ describe('ButtonComponent', () => {
65
65
  });
66
66
 
67
67
  it('should apply primary variant classes by default (SFN / export)', () => {
68
- expect(button.className).toContain('bg-export-strong');
69
- expect(button.className).toContain('text-white');
68
+ const tokens = button.className.split(/\s+/);
69
+ expect(tokens).toContain('bg-export');
70
+ expect(tokens).toContain('text-white');
71
+ expect(tokens).not.toContain('bg-export-strong');
70
72
  });
71
73
 
72
74
  it('should switch primary to import orange when mode is STN', () => {
73
75
  mode.set('stn');
74
76
  fixture.detectChanges();
75
77
 
76
- expect(button.className).toContain('bg-import-strong');
77
- expect(button.className).not.toContain('bg-export-strong');
78
+ const tokens = button.className.split(/\s+/);
79
+ expect(tokens).toContain('bg-import-strong');
80
+ expect(tokens).not.toContain('bg-export');
78
81
  });
79
82
 
80
83
  it('should switch ghost-primary text accent with shipping mode', () => {
81
84
  host.variant.set('ghost-primary');
82
85
  fixture.detectChanges();
83
- expect(button.className).toContain('text-export-strong');
84
- expect(button.className).toContain('bg-transparent');
86
+ let tokens = button.className.split(/\s+/);
87
+ expect(tokens).toContain('text-export');
88
+ expect(tokens).toContain('bg-transparent');
85
89
 
86
90
  mode.set('stn');
87
91
  fixture.detectChanges();
88
92
 
89
- expect(button.className).toContain('text-import-strong');
90
- expect(button.className).not.toContain('text-export-strong');
93
+ tokens = button.className.split(/\s+/);
94
+ expect(tokens).toContain('text-import-strong');
95
+ expect(tokens).not.toContain('text-export');
91
96
  });
92
97
 
93
98
  it('should switch variant and size classes', () => {