@elasticias/ui 1.0.41 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elasticias/ui",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0",
@@ -45,6 +45,24 @@
45
45
  --m-finance: #0d6e6a;
46
46
  --m-admin: #0f1115;
47
47
 
48
+ /* ── Crescilio brand colours ─────────────────────────────────────
49
+ These are the Crescilio brand colours: one per product, plus a
50
+ critical tone reserved for the system. The Crescilio Brand
51
+ Guidelines will be shared later, when the logo is ready; until
52
+ then these values are the reference.
53
+ Each colour comes as a pair named for the ground it sits on: the
54
+ plain name is for use on ink (dark grounds), `-paper` for use on
55
+ paper (light grounds). They are fixed values, not theme-switched,
56
+ so they are not restated under `.p-dark`. */
57
+ --cr-spring: #00D19A; /* Crescilio ERP, on ink */
58
+ --cr-spring-paper: #007A5A; /* Crescilio ERP, on paper */
59
+ --cr-sun: #FFCE3B; /* Crescilio POS, on ink */
60
+ --cr-sun-paper: #A87800; /* Crescilio POS, on paper */
61
+ --cr-violet: #7C5CFF; /* Crescilio Store, on ink */
62
+ --cr-violet-paper: #5B3FE0; /* Crescilio Store, on paper */
63
+ --cr-critical: #FF5C35; /* Coral, critical, system only, on ink */
64
+ --cr-critical-paper: #C2381A; /* Coral, critical, system only, on paper */
65
+
48
66
  /* ── Status pairs (chips only) ───────────────────────────────── */
49
67
  --st-pending-fg: #b34a00; --st-pending-bg: #fff1e0;
50
68
  --st-processing-fg: #1356a8; --st-processing-bg: #e0ecfc;
@@ -765,12 +765,24 @@
765
765
  /* ──────────── RESULTS BAR + TABLE WRAPPER ──────────────────────── */
766
766
 
767
767
  .tbl-wrap {
768
+ min-width: 0;
768
769
  background: var(--paper-alt);
769
770
  border: 1px solid var(--rule);
770
771
  border-radius: var(--r-2xl);
771
772
  overflow: hidden;
772
773
  }
773
774
 
775
+ /* The table's own horizontal scroller, inside the clipping shell. A table
776
+ wider than its column (a tablet, or a desktop with the side panel open)
777
+ pans here rather than being cut off by .tbl-wrap or widening the page.
778
+ overscroll-behavior keeps a sideways drag that hits the end from
779
+ panning the page behind it. */
780
+ .tbl-scroll {
781
+ min-width: 0;
782
+ overflow-x: auto;
783
+ overscroll-behavior-x: contain;
784
+ }
785
+
774
786
  .tbl-head {
775
787
  display: flex;
776
788
  justify-content: space-between;
@@ -841,7 +853,10 @@
841
853
  }
842
854
 
843
855
  .tbl tbody td {
844
- padding: 14px 18px;
856
+ /* Published so a control inside the cell can size a touch slop that
857
+ stays inside its own row (see the toggle switch, pointer: coarse). */
858
+ --tbl-cell-pad-block: 14px;
859
+ padding: var(--tbl-cell-pad-block) 18px;
845
860
  border-bottom: 1px solid var(--rule-soft, rgba(15, 17, 21, 0.05));
846
861
  vertical-align: middle;
847
862
  }
@@ -968,49 +983,66 @@
968
983
  }
969
984
 
970
985
  /* ──────────── APP-BAR ICON ACTIONS ──────────────────────────────
971
- The theme switch and sign-out sit at the trailing edge of
972
- ef-app-top. They borrow the row-actions trigger's shape rather
973
- than inventing a third kind of icon button. */
986
+ The theme switch, sign-out and any app action (`.ef-app-top__action`)
987
+ at the trailing edge of ef-app-top, and the theme switch in the login
988
+ header. Plain icons in the treatment of the phone's menu button
989
+ (`.ef-app-shell__menu`): no fill, no border, a 40px box, an 18px glyph.
990
+
991
+ They used to borrow the row-actions trigger's bordered pill, and the
992
+ touch tier grew that painted pill to 48px, so a tablet's top bar was a
993
+ row of big circles. The touch target now grows invisibly instead (see
994
+ the `pointer: coarse` block below): a thumb needs 48px, an eye does not.
995
+ The slot gap is 8px, so two 48px targets meet edge to edge and never
996
+ overlap.
997
+
998
+ Each carries an aria-label and a pTooltip (hover and focus), not a
999
+ `title`: a title never shows on touch and doubles PrimeNG's tooltip on
1000
+ a desktop. */
974
1001
 
975
1002
  .ef-theme-toggle,
976
1003
  .ef-app-top__logout,
977
1004
  .ef-app-top__action {
978
1005
  appearance: none;
979
- background: var(--paper-alt);
980
- border: 1px solid var(--rule);
981
- width: var(--hit);
982
- height: var(--hit);
983
- border-radius: var(--r-pill);
1006
+ position: relative;
1007
+ flex: 0 0 auto;
1008
+ background: transparent;
1009
+ border: 0;
1010
+ padding: 0;
1011
+ width: var(--hit-base);
1012
+ height: var(--hit-base);
1013
+ border-radius: var(--r-md);
984
1014
  display: inline-grid;
985
1015
  place-items: center;
986
1016
  color: var(--text-mute);
987
1017
  cursor: pointer;
988
1018
  transition:
989
1019
  background var(--t-fast) var(--ease-out),
990
- border-color var(--t-fast) var(--ease-out),
991
1020
  color var(--t-fast) var(--ease-out);
992
1021
  }
993
1022
 
994
- .ef-theme-toggle:hover,
995
- .ef-app-top__logout:hover,
996
- .ef-app-top__action:hover {
997
- color: var(--text);
998
- border-color: var(--rule-hover);
1023
+ /* Only where hover is real: iOS keeps :hover on the last element tapped,
1024
+ so the fill would stay on that icon until the next tap elsewhere. */
1025
+ @media (hover: hover) {
1026
+ .ef-theme-toggle:hover,
1027
+ .ef-app-top__logout:hover,
1028
+ .ef-app-top__action:hover {
1029
+ background: color-mix(in srgb, var(--text) 8%, transparent);
1030
+ color: var(--text);
1031
+ }
999
1032
  }
1000
1033
 
1001
1034
  .ef-theme-toggle:focus-visible,
1002
1035
  .ef-app-top__logout:focus-visible,
1003
1036
  .ef-app-top__action:focus-visible {
1004
- outline: 0;
1005
- border-color: var(--tenant-400);
1006
- box-shadow: 0 0 0 4px var(--tenant-100);
1037
+ outline: 2px solid var(--tenant-400);
1038
+ outline-offset: 2px;
1007
1039
  color: var(--text);
1008
1040
  }
1009
1041
 
1010
1042
  .ef-theme-toggle i,
1011
1043
  .ef-app-top__logout i,
1012
1044
  .ef-app-top__action i {
1013
- font-size: 14px;
1045
+ font-size: 18px;
1014
1046
  line-height: 1;
1015
1047
  }
1016
1048
 
@@ -1551,6 +1583,18 @@
1551
1583
  inset-inline-start: 0;
1552
1584
  }
1553
1585
 
1586
+ /* Placed by ef-row-actions from the trigger's rect (inline top / right /
1587
+ bottom / left), so no scrolling or clipping ancestor can cut it off. */
1588
+ .row-actions__menu.is-floating {
1589
+ position: fixed;
1590
+ /* max-height is set inline from the room on the menu's side; border-box
1591
+ so the padding and border count inside it and a capped menu stays on
1592
+ screen. */
1593
+ box-sizing: border-box;
1594
+ overflow-y: auto;
1595
+ overscroll-behavior: contain;
1596
+ }
1597
+
1554
1598
  /* Not enough room below the trigger — flip above it, and reverse the
1555
1599
  entry slide so the menu still moves away from its trigger. */
1556
1600
  .row-actions__menu.up {
@@ -1792,9 +1836,12 @@
1792
1836
  min-width: 0;
1793
1837
  }
1794
1838
 
1795
- /* When a row-actions menu is open inside a data card, the table-wrap
1796
- should let the popover escape its overflow. The data-card binds
1797
- .has-open-menu when any descendant trigger is in `.open` state. */
1839
+ /* While the density or columns menu (in .tbl-head) is open, the
1840
+ table-wrap lets it escape its rounded clip; the data-card binds
1841
+ .has-open-menu for those two only. Row menus never need it: they are
1842
+ fixed to the viewport, because .tbl-scroll must keep its own overflow
1843
+ (lifting it would reset the reader's scroll position and spill the
1844
+ table across the page). */
1798
1845
  .tbl-wrap.has-open-menu {
1799
1846
  overflow: visible;
1800
1847
  }
@@ -4538,9 +4585,6 @@ input.ef-input[type='number'] {
4538
4585
  min-inline-size: var(--hit-touch);
4539
4586
  }
4540
4587
 
4541
- .ef-app-top__action,
4542
- .ef-theme-toggle,
4543
- .ef-app-top__logout,
4544
4588
  .row-actions__trigger,
4545
4589
  .ef-clear,
4546
4590
  .pg {
@@ -4548,12 +4592,65 @@ input.ef-input[type='number'] {
4548
4592
  block-size: var(--hit-touch);
4549
4593
  }
4550
4594
 
4551
- /* Toolbar buttons collapse to icon-only below 767px, so the blanket
4552
- min-block-size above stretched a 40px-wide button to 48px tall and
4553
- produced a lozenge four-across in the header. Here the VISUAL stays
4554
- 40px square and the TOUCH TARGET reaches the tier through a hit
4555
- slop, which is the point of the tier: a thumb needs 48px, an eye
4556
- does not. */
4595
+ /* The top-bar icons keep their 40px painted box and reach the 48px
4596
+ tier through an invisible overhang, 4px each side. The 8px slot gap
4597
+ means neighbouring overhangs meet and never overlap, so a tap always
4598
+ lands on the control nearest it. */
4599
+ .ef-app-top__action::after,
4600
+ .ef-theme-toggle::after,
4601
+ .ef-app-top__logout::after {
4602
+ content: '';
4603
+ position: absolute;
4604
+ inset: calc((var(--hit-touch) - var(--hit-base)) / -2);
4605
+ }
4606
+
4607
+ /* Where the lib's controls meet whatever the app projects into the
4608
+ actions slot, the gap is 12px rather than 8. An app control can carry
4609
+ a wider overhang than ours: the phone avatar paints 32px inside a
4610
+ 48px target, 8px each side. 8 + 4 needs 12px between the painted
4611
+ boxes, or the theme switch takes the avatar's trailing edge. */
4612
+ ef-app-top .ef-app-top__slot--actions > * + ef-theme-toggle,
4613
+ ef-app-top .ef-app-top__slot--actions > :not(ef-theme-toggle) + .ef-app-top__logout {
4614
+ margin-inline-start: 4px;
4615
+ }
4616
+
4617
+ /* The switch draws at its theme size (Aura: 40x24) and its click
4618
+ target is PrimeNG's invisible input, sized to exactly that box. In a
4619
+ list row a tap that lands just outside it did nothing, because the
4620
+ row wrapper stops propagation. Grow the invisible input towards
4621
+ 48x48 around the switch; the visual does not change. The switch
4622
+ root is position: relative with no overflow clip, and a tap on the
4623
+ overhang still reaches PrimeNG's host click handler.
4624
+
4625
+ Vertically, the overhang never exceeds the cell's own block padding
4626
+ (`--tbl-cell-pad-block`, set by the table and its density presets).
4627
+ A compact row is about 33px, so a full 12px overhang reached into the
4628
+ next row and a tap on one client's switch toggled its neighbour's.
4629
+ Outside a table the variable is unset and the full slop applies. */
4630
+ ef-toggleswitch .p-toggleswitch-input {
4631
+ --ef-switch-slop-block: calc((var(--hit-touch) - var(--p-toggleswitch-height, 1.5rem)) / 2);
4632
+ --ef-switch-slop-inline: calc((var(--hit-touch) - var(--p-toggleswitch-width, 2.5rem)) / 2);
4633
+ inset-block: calc(-1 * min(var(--ef-switch-slop-block), var(--tbl-cell-pad-block, var(--ef-switch-slop-block))));
4634
+ inset-inline: calc(-1 * var(--ef-switch-slop-inline));
4635
+ width: auto;
4636
+ height: auto;
4637
+ }
4638
+ }
4639
+
4640
+
4641
+ /* Toolbar buttons collapse to icon-only below 767px, so the blanket
4642
+ min-block-size above stretched a 40px-wide button to 48px tall and
4643
+ produced a lozenge four-across in the header. Here the VISUAL stays
4644
+ 40px square and the TOUCH TARGET reaches the tier through a hit
4645
+ slop, which is the point of the tier: a thumb needs 48px, an eye
4646
+ does not.
4647
+
4648
+ Scoped to the same 767px as the rule that hides the label. Keyed on
4649
+ pointer type alone it also caught every tablet, which kept its label
4650
+ and got a 40px box: "Nouvelle commande" spilled out of the button and
4651
+ the detail actions piled into each other. Above 767px a touch screen
4652
+ keeps the labelled button, 48px tall from the generic rule above. */
4653
+ @media (pointer: coarse) and (max-width: 767px) {
4557
4654
  .detail-toolbar .right .btn,
4558
4655
  .search-toolbar .right .btn {
4559
4656
  position: relative;
@@ -4573,7 +4670,6 @@ input.ef-input[type='number'] {
4573
4670
  }
4574
4671
  }
4575
4672
 
4576
-
4577
4673
  /* ── MOBILE BOTTOM BAR ──────────────────────────────────────────────
4578
4674
  The phone shell renders a 64px tab bar fixed to the bottom edge.
4579
4675
  Anything else pinned down there has to clear it, so the height is
@@ -2,7 +2,7 @@ import * as _angular_core from '@angular/core';
2
2
  import { PipeTransform, OnInit, OnChanges, TemplateRef, EventEmitter, AfterContentInit, OnDestroy, SimpleChanges, InjectionToken, AfterViewInit } from '@angular/core';
3
3
  import * as _elasticias_screens from '@elasticias/screens';
4
4
  import { EfDataCardColumn, ScreenContext, EfDetailToolbarAction, EfSearchToolbarAction, EfDataCardSort, EfDataCardExportRequest, EfDateRange, EfDatePresetKey } from '@elasticias/screens';
5
- export { EfDataCardColumn, EfDataCardColumnAlign, EfDataCardColumnMobileRole, EfDataCardColumnType, EfDataCardSort, EfDataCardSortDirection, EfDatePresetKey, EfDateRange, EfDetailToolbarAction, EfSearchToolbarAction } from '@elasticias/screens';
5
+ export { EfBoundedDateRange, EfDataCardColumn, EfDataCardColumnAlign, EfDataCardColumnMobileRole, EfDataCardColumnType, EfDataCardSort, EfDataCardSortDirection, EfDatePresetKey, EfDateRange, EfDetailToolbarAction, EfSearchToolbarAction } from '@elasticias/screens';
6
6
  import { Menu } from 'primeng/menu';
7
7
  import * as _elasticias_core from '@elasticias/core';
8
8
  import { EfBuildPackage, EfModule, EfNavSection, EfNavItem, EfModuleId, EfToast, EfToastAction, EfThemeConfigService } from '@elasticias/core';
@@ -980,6 +980,9 @@ declare class EfConfirmDialogComponent {
980
980
  * The icon shows the theme you would move to, not the one you are in, which
981
981
  * is what makes a single-button toggle readable: a moon means "go dark".
982
982
  *
983
+ * Named by `aria-label` and a pTooltip that opens on hover and on
984
+ * keyboard focus (not `title`, which never shows on touch).
985
+ *
983
986
  * ```html
984
987
  * <ef-theme-toggle />
985
988
  * ```
@@ -990,13 +993,18 @@ declare class EfThemeToggleComponent {
990
993
  readonly darkIcon: _angular_core.InputSignal<string>;
991
994
  /** Icon shown while dark is active (i.e. "switch to light"). */
992
995
  readonly lightIcon: _angular_core.InputSignal<string>;
993
- /** Translation key for the accessible name. */
996
+ /**
997
+ * Where the tooltip opens. Below suits a top bar (the app bar, the
998
+ * login header); a toggle placed low on a page can open it above.
999
+ */
1000
+ readonly tooltipPosition: _angular_core.InputSignal<"top" | "left" | "bottom" | "right">;
1001
+ /** Translation key for the accessible name (also the tooltip text). */
994
1002
  readonly ariaLabelKey: _angular_core.InputSignal<string>;
995
1003
  readonly isDark: _angular_core.Signal<boolean>;
996
1004
  protected readonly labelKey: _angular_core.Signal<string>;
997
1005
  toggle(): void;
998
1006
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EfThemeToggleComponent, never>;
999
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EfThemeToggleComponent, "ef-theme-toggle", never, { "darkIcon": { "alias": "darkIcon"; "required": false; "isSignal": true; }; "lightIcon": { "alias": "lightIcon"; "required": false; "isSignal": true; }; "ariaLabelKey": { "alias": "ariaLabelKey"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1007
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EfThemeToggleComponent, "ef-theme-toggle", never, { "darkIcon": { "alias": "darkIcon"; "required": false; "isSignal": true; }; "lightIcon": { "alias": "lightIcon"; "required": false; "isSignal": true; }; "tooltipPosition": { "alias": "tooltipPosition"; "required": false; "isSignal": true; }; "ariaLabelKey": { "alias": "ariaLabelKey"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1000
1008
  }
1001
1009
 
1002
1010
  /**
@@ -1579,7 +1587,8 @@ declare class EfToolbarComponent {
1579
1587
  *
1580
1588
  * **Desktop / tablet:** rail (64px) + side (240px) + (top + main). The
1581
1589
  * side folds away from a toggle at the foot of the rail (or mod+B); the
1582
- * rail never does.
1590
+ * rail never does. A tablet starts with it folded unless the viewer has
1591
+ * a stored choice (`EF_SIDE_COLLAPSED_KEY`).
1583
1592
  * **Mobile:** delegates to `<ef-app-shell-mobile>` — top bar + scrollable
1584
1593
  * body + 5-tab bottom bar + FAB slot.
1585
1594
  *
@@ -1601,7 +1610,20 @@ declare class EfAppShellComponent {
1601
1610
  readonly isMobile: _angular_core.Signal<boolean>;
1602
1611
  readonly showSide: _angular_core.Signal<boolean>;
1603
1612
  private readonly prefs;
1604
- readonly sideCollapsed: _angular_core.WritableSignal<boolean>;
1613
+ /** The viewer's explicit choice ('1' folded, '0' open), or null when they never made one. */
1614
+ private readonly storedSide;
1615
+ /**
1616
+ * Folded or open. An explicit choice always wins. Without one, a
1617
+ * tablet starts folded: at 768-1279px the 240px panel left a
1618
+ * phone-width column for a desktop table, so the right-hand columns
1619
+ * were cut off. A desktop keeps it open and a phone never renders it.
1620
+ *
1621
+ * The default is derived, never written: storing it would turn it
1622
+ * into a choice the viewer did not make, pin it when they rotate or
1623
+ * resize across the breakpoint, and with a server-backed store send
1624
+ * a request on every page load.
1625
+ */
1626
+ readonly sideCollapsed: _angular_core.Signal<boolean>;
1605
1627
  /** Shown in the toggle's tooltip: the button is far from the content, the shortcut is not. */
1606
1628
  readonly shortcutHint: string;
1607
1629
  toggleSide(): void;
@@ -1727,6 +1749,21 @@ declare class EfAppTopComponent {
1727
1749
  /** Present only when the app provides `EF_SESSION`. */
1728
1750
  protected readonly session: _elasticias_core.EfSession;
1729
1751
  protected signOut(): void;
1752
+ /** A touch or pen press at least this long is a hold, not a tap. */
1753
+ static readonly HOLD_MS = 500;
1754
+ /** True on a screen whose primary pointer cannot hover (a phone, a tablet). */
1755
+ protected readonly touchOnly: _angular_core.WritableSignal<boolean>;
1756
+ private pressStart;
1757
+ constructor();
1758
+ protected onSignOutPointerDown(event: PointerEvent): void;
1759
+ /**
1760
+ * A cancelled press (the browser took the gesture) must not judge a
1761
+ * later click. Not on pointerleave: on touch it fires after pointerup
1762
+ * and before the synthesised click, so clearing there would erase
1763
+ * every long press just before the guard reads it.
1764
+ */
1765
+ protected forgetSignOutPress(): void;
1766
+ protected onSignOutClick(event: MouseEvent): void;
1730
1767
  private readonly active;
1731
1768
  readonly module: _angular_core.Signal<_elasticias_core.EfModule>;
1732
1769
  readonly navItem: _angular_core.Signal<_elasticias_core.EfNavItem>;
@@ -4826,11 +4863,6 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4826
4863
  private storageKey;
4827
4864
  private loadPreferences;
4828
4865
  private savePreferences;
4829
- /** Tracks how many `ef-row-actions` are currently open inside this
4830
- * card. When > 0, `.tbl-wrap` lifts its `overflow: hidden` so the
4831
- * popup can escape its rounded edges. */
4832
- readonly openMenuCount: _angular_core.WritableSignal<number>;
4833
- onRowActionsToggle(event: Event): void;
4834
4866
  /**
4835
4867
  * Children that own their own click. Opening the row on top of them would
4836
4868
  * run two things from one gesture.
@@ -5003,6 +5035,9 @@ declare class EfOverflowTooltipDirective {
5003
5035
  * - Click the trigger to toggle. Trigger gets `.open` (ink-active) while the menu is open.
5004
5036
  * - Only one row menu is open at a time — opening one closes the last.
5005
5037
  * - The menu flips above the trigger when there isn't room below it.
5038
+ * - The menu is fixed to the viewport, placed from the trigger's rect, so a
5039
+ * table's horizontal scroller cannot clip it. Scrolling any ancestor or
5040
+ * resizing the window closes it, rather than leaving it behind its row.
5006
5041
  * - Click outside or press `Escape` to close.
5007
5042
  * - Clicking an item runs its `command` then closes the menu.
5008
5043
  * - dblclick on the trigger or menu does NOT propagate, so the data-card's
@@ -5077,14 +5112,54 @@ declare class EfRowActionsComponent {
5077
5112
  * below wins, which is where it has always been.
5078
5113
  */
5079
5114
  private shouldDropUp;
5115
+ /** Gap between the trigger and the menu. Matches the CSS `calc(100% + 8px)`. */
5116
+ private static readonly MENU_GAP;
5117
+ /**
5118
+ * Where the fixed menu sits, as physical offsets from the viewport
5119
+ * edges. The four values are always set, so they override the CSS
5120
+ * `top` / `bottom` / `inset-inline-*` an absolute menu uses.
5121
+ */
5122
+ readonly menuPosition: _angular_core.WritableSignal<{
5123
+ top: string;
5124
+ right: string;
5125
+ bottom: string;
5126
+ left: string;
5127
+ maxHeight: string;
5128
+ }>;
5129
+ /**
5130
+ * Fixed rather than absolute: inside ef-data-card the table sits in a
5131
+ * horizontal scroller, and `overflow-x: auto` makes the block axis clip
5132
+ * too, so an absolute menu was cut off at the scroller's edge. Lifting
5133
+ * the scroller's overflow while a menu is open would reset its
5134
+ * scrollLeft and spill the table across the page, exactly when the
5135
+ * reader has scrolled across to reach the actions column.
5136
+ */
5137
+ private place;
5138
+ /**
5139
+ * An ancestor with a transform, filter or containment becomes the fixed
5140
+ * menu's containing block (a dialog mid-animation, for one), and the
5141
+ * viewport offsets land in the wrong place. Measure where the menu
5142
+ * actually is against where the trigger says it should be, and shift
5143
+ * by the difference. Also nudges it back inside the viewport.
5144
+ */
5145
+ private correctOffset;
5146
+ /** The nearest `dir` wins (the app sets it on <html>); computed style covers a page without one. */
5147
+ private isRtl;
5148
+ private triggerRect;
5149
+ /** The fixed containing block: the viewport without its scrollbars. */
5150
+ private static viewportWidth;
5151
+ private static viewportHeight;
5152
+ private displacementListener;
5153
+ private listenForDisplacement;
5154
+ private stopListeningForDisplacement;
5080
5155
  /** Rough height before the menu exists: item padding + line box, with
5081
5156
  * dividers and the menu's own padding and border. */
5082
5157
  private estimateMenuHeight;
5083
5158
  /** Re-decide against the rendered height — item labels wrap, and the
5084
5159
  * estimate can't know that. */
5085
5160
  private correctPlacementAfterRender;
5086
- /** Bubbling DOM event so ancestors (e.g. ef-data-card) can react —
5087
- * see `.tbl-wrap.has-open-menu { overflow: visible }`. */
5161
+ /** Bubbling DOM event so ancestors can react to a row menu opening or
5162
+ * closing. ef-data-card no longer needs it (the menu is fixed). */
5088
5163
  private dispatchToggle;
5089
5164
  /** Outside click — closes the menu. */
5090
5165
  onDocumentClick(event: MouseEvent): void;
@@ -5694,7 +5769,9 @@ type EfDateFieldValue = Date | [Date, Date] | null;
5694
5769
  * Built-in presets (computed from `today` at open time):
5695
5770
  * `today`, `this_week`, `this_month`, `last_30_days`, `last_90_days`,
5696
5771
  * `this_quarter`, `this_year`. Override with `[presets]="customList"`
5697
- * if you need a different set.
5772
+ * if you need a different set. `all_time` (no bounds, emitted as null
5773
+ * start and end) is also recognised, and offered first in the default
5774
+ * list with `allowAllTime`.
5698
5775
  */
5699
5776
  declare class EfDatepickerAdvancedComponent extends AbstractEfFormControl implements ControlValueAccessor, AfterViewInit {
5700
5777
  private readonly host;
@@ -5741,6 +5818,15 @@ declare class EfDatepickerAdvancedComponent extends AbstractEfFormControl implem
5741
5818
  readonly end: _angular_core.InputSignal<Date>;
5742
5819
  /** Show a `'Personnalisé…'` row that opens the calendar view. */
5743
5820
  readonly allowCustomRange: _angular_core.InputSignalWithTransform<boolean, unknown>;
5821
+ /**
5822
+ * Offer an `all_time` row ("Toute la période") at the top of the
5823
+ * default preset list. Picking it emits `start: null, end: null`.
5824
+ * Off by default because a report screen needs a bounded period;
5825
+ * list screens whose search treats null dates as "no filter" turn
5826
+ * it on so the user can get back to the unfiltered list. Ignored
5827
+ * when `[presets]` is supplied.
5828
+ */
5829
+ readonly allowAllTime: _angular_core.InputSignalWithTransform<boolean, unknown>;
5744
5830
  /** Component behaviour: smart-bar filter vs. form field. */
5745
5831
  readonly mode: _angular_core.InputSignal<"filter" | "field">;
5746
5832
  /** Field mode only — pick a single date or a `[start, end]` range. */
@@ -5917,6 +6003,7 @@ declare class EfDatepickerAdvancedComponent extends AbstractEfFormControl implem
5917
6003
  /** Assemble an EfDateRange — exposes `labelKey` (for the trigger
5918
6004
  * to render via `| translate`) and a literal `label` fallback. */
5919
6005
  private buildRange;
6006
+ private static readonly BUILT_IN_KEYS;
5920
6007
  private builtInRange;
5921
6008
  private builtInHint;
5922
6009
  /** 6 weeks × 7 days. Each cell carries its date + flags. */
@@ -5940,7 +6027,7 @@ declare class EfDatepickerAdvancedComponent extends AbstractEfFormControl implem
5940
6027
  }) => number;
5941
6028
  trackByDow: (_: number, label: string) => string;
5942
6029
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EfDatepickerAdvancedComponent, never>;
5943
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EfDatepickerAdvancedComponent, "ef-datepicker-advanced", never, { "triggerLabelKey": { "alias": "triggerLabelKey"; "required": false; "isSignal": true; }; "triggerLabel": { "alias": "triggerLabel"; "required": false; "isSignal": true; }; "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "activePreset": { "alias": "activePreset"; "required": false; "isSignal": true; }; "start": { "alias": "start"; "required": false; "isSignal": true; }; "end": { "alias": "end"; "required": false; "isSignal": true; }; "allowCustomRange": { "alias": "allowCustomRange"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "showTime": { "alias": "showTime"; "required": false; "isSignal": true; }; }, { "rangeChange": "rangeChange"; "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
6030
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EfDatepickerAdvancedComponent, "ef-datepicker-advanced", never, { "triggerLabelKey": { "alias": "triggerLabelKey"; "required": false; "isSignal": true; }; "triggerLabel": { "alias": "triggerLabel"; "required": false; "isSignal": true; }; "presets": { "alias": "presets"; "required": false; "isSignal": true; }; "activePreset": { "alias": "activePreset"; "required": false; "isSignal": true; }; "start": { "alias": "start"; "required": false; "isSignal": true; }; "end": { "alias": "end"; "required": false; "isSignal": true; }; "allowCustomRange": { "alias": "allowCustomRange"; "required": false; "isSignal": true; }; "allowAllTime": { "alias": "allowAllTime"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "selectionMode": { "alias": "selectionMode"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "showTime": { "alias": "showTime"; "required": false; "isSignal": true; }; }, { "rangeChange": "rangeChange"; "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
5944
6031
  }
5945
6032
 
5946
6033
  /**