@elasticias/ui 1.0.49 → 1.0.51

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.49",
3
+ "version": "1.0.51",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0",
@@ -890,6 +890,8 @@
890
890
  font-family: var(--font-mono);
891
891
  font-size: 12px;
892
892
  font-weight: 700;
893
+ /* Hyphenated codes (HA-100) break at the hyphen otherwise. */
894
+ white-space: nowrap;
893
895
  }
894
896
 
895
897
  .tbl .num {
@@ -2071,16 +2073,27 @@
2071
2073
  }
2072
2074
 
2073
2075
  .dp__panel {
2074
- position: absolute;
2075
- top: calc(100% + 8px);
2076
- inset-inline-start: 0;
2077
- min-width: 320px;
2076
+ /* Portaled to <body> and fixed to the viewport; the component writes all
2077
+ four physical sides and max-height from the trigger's rect
2078
+ (placeDpPanel). No logical inset here: in RTL it would fight the
2079
+ computed left. The z-index is a fallback; PrimeNG's ZIndexUtils sets
2080
+ the live layer. */
2081
+ position: fixed;
2082
+ box-sizing: border-box;
2083
+ /* The preset list sizes to its rows; the calendar view (.wide) has a set
2084
+ width. It used to take the date inputs' intrinsic width (about 450px),
2085
+ which is what pushed it past the card and the viewport. */
2086
+ inline-size: max-content;
2087
+ min-inline-size: 320px;
2088
+ max-inline-size: calc(100vw - 16px);
2089
+ overflow-y: auto;
2090
+ overscroll-behavior: contain;
2078
2091
  background: var(--paper-alt);
2079
2092
  border: 1px solid var(--rule);
2080
2093
  border-radius: var(--r-xl);
2081
2094
  box-shadow: var(--shadow-3);
2082
2095
  padding: 6px;
2083
- z-index: 40;
2096
+ z-index: 1000;
2084
2097
  display: none;
2085
2098
  animation: row-actions-menu-in var(--t-base) var(--ease-spring);
2086
2099
  }
@@ -2090,7 +2103,7 @@
2090
2103
  gap: 2px;
2091
2104
  }
2092
2105
  .dp__panel.wide {
2093
- min-width: 340px;
2106
+ inline-size: 340px;
2094
2107
  }
2095
2108
 
2096
2109
  .dp__view {
@@ -2365,7 +2378,7 @@
2365
2378
 
2366
2379
  .dp__cal-grid {
2367
2380
  display: grid;
2368
- grid-template-columns: repeat(7, 1fr);
2381
+ grid-template-columns: repeat(7, minmax(0, 1fr));
2369
2382
  gap: 2px 0;
2370
2383
  padding: 0 2px;
2371
2384
  }
@@ -2460,20 +2473,24 @@
2460
2473
 
2461
2474
  .dp__inputs {
2462
2475
  display: grid;
2463
- grid-template-columns: 1fr 1fr;
2476
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
2477
+ /* A label that wraps (the panel has a set width now) must not push its
2478
+ input below its neighbour's. */
2479
+ align-items: end;
2464
2480
  gap: var(--s-2);
2465
2481
  padding: var(--s-2) var(--s-3) 0;
2466
2482
  }
2467
2483
 
2468
2484
  /* Single-date field mode — one full-width input instead of Du / Au. */
2469
2485
  .dp__inputs--single {
2470
- grid-template-columns: 1fr;
2486
+ grid-template-columns: minmax(0, 1fr);
2471
2487
  padding-bottom: var(--s-3);
2472
2488
  }
2473
2489
 
2474
2490
  .dp__field {
2475
2491
  display: grid;
2476
2492
  gap: 4px;
2493
+ min-width: 0;
2477
2494
  }
2478
2495
 
2479
2496
  .dp__field label {
@@ -2486,6 +2503,9 @@
2486
2503
  }
2487
2504
 
2488
2505
  .dp__field input {
2506
+ /* Border-box here, not left to an app's reset: with content-box the
2507
+ 100% width plus padding pushed the time input past its column. */
2508
+ box-sizing: border-box;
2489
2509
  font: inherit;
2490
2510
  font-family: var(--font-mono);
2491
2511
  font-size: 12.5px;
@@ -2806,11 +2826,17 @@
2806
2826
  flex-wrap: wrap;
2807
2827
  }
2808
2828
 
2829
+ /* The identity takes a real basis, not 0: with `flex: 1` it always "fit",
2830
+ so a screen with many actions squeezed it to a sliver and cut its notices
2831
+ ("Prise en charge par ...") to an ellipsis. Now, when the identity and the
2832
+ actions cannot share a row at that width, the actions wrap onto a row of
2833
+ their own and the identity keeps the whole line. A screen may tune the
2834
+ basis with --detail-toolbar-identity-min. */
2809
2835
  .detail-toolbar .left {
2810
2836
  display: flex;
2811
2837
  align-items: center;
2812
2838
  gap: 10px;
2813
- flex: 1;
2839
+ flex: 1 1 var(--detail-toolbar-identity-min, 22rem);
2814
2840
  min-width: 0;
2815
2841
  flex-wrap: wrap;
2816
2842
  }
@@ -2826,6 +2852,22 @@
2826
2852
  color: var(--text-soft);
2827
2853
  }
2828
2854
 
2855
+ /* Keeps its width: removing it would narrow the group and let it unwrap. */
2856
+ .detail-toolbar .sep.is-hidden {
2857
+ visibility: hidden;
2858
+ }
2859
+
2860
+ /* Print … Save travel together with their separator, so a wrap never leaves
2861
+ the "|" at the end of one row and Save alone on the next. The group keeps
2862
+ the far end of its row, like Save on a phone. */
2863
+ .detail-toolbar .std {
2864
+ display: inline-flex;
2865
+ align-items: center;
2866
+ gap: 6px;
2867
+ flex-wrap: nowrap;
2868
+ margin-inline-start: auto;
2869
+ }
2870
+
2829
2871
  .detail-toolbar .right {
2830
2872
  display: flex;
2831
2873
  align-items: center;
@@ -3835,6 +3877,22 @@ input.ef-input[type='number'] {
3835
3877
  transform: translateY(-50%);
3836
3878
  }
3837
3879
 
3880
+ /* The clear sits at the wrapper's trailing edge, but the input can carry its
3881
+ own direction (`dir` on ef-input-text: an LTR phone or IBAN on an Arabic
3882
+ screen), and `padding-inline-end` follows the input, so the room it reserved
3883
+ landed on the opposite side and the value ran under the ✕. Reserve the room
3884
+ by the wrapper's direction instead. Physical sides on purpose: the two
3885
+ directions are named so the side tracks the clear, not the input. */
3886
+ .ef-input-wrap:dir(ltr) .ef-input.has-clear {
3887
+ padding-left: 12px;
3888
+ padding-right: 36px;
3889
+ }
3890
+
3891
+ .ef-input-wrap:dir(rtl) .ef-input.has-clear {
3892
+ padding-left: 36px;
3893
+ padding-right: 12px;
3894
+ }
3895
+
3838
3896
  /* The same centring, for the clear that PrimeNG owns rather than we do.
3839
3897
  PrimeNG centres both password icons with `top: 50%; margin-top: -8px`, which
3840
3898
  is exact for the 16px mask toggle it draws itself and wrong for anything
@@ -4702,6 +4760,74 @@ input.ef-input[type='number'] {
4702
4760
  }
4703
4761
  }
4704
4762
 
4763
+ /* The date picker's phone layout: a full-width bottom sheet over a backdrop.
4764
+ EfViewportService's mobile (<= 767px) toggles the class, so there is no
4765
+ media query here and no band where the two disagree. Every target is
4766
+ --hit-touch (48px). Declared after the base .dp__* rules so it wins. */
4767
+ .dp__backdrop {
4768
+ position: fixed;
4769
+ inset: 0;
4770
+ z-index: 1000;
4771
+ background: color-mix(in oklab, var(--ink-950) 35%, transparent);
4772
+ }
4773
+
4774
+ .dp__panel.dp__panel--sheet {
4775
+ inset: auto 0 0 0;
4776
+ inline-size: 100%;
4777
+ max-inline-size: none;
4778
+ min-inline-size: 0;
4779
+ max-height: 85vh;
4780
+ max-height: 85dvh;
4781
+ border-radius: var(--r-xl) var(--r-xl) 0 0;
4782
+ border-bottom: 0;
4783
+ padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
4784
+ animation: dp-sheet-in var(--t-base) var(--ease-spring);
4785
+ }
4786
+
4787
+ @keyframes dp-sheet-in {
4788
+ from {
4789
+ transform: translateY(100%);
4790
+ }
4791
+ to {
4792
+ transform: translateY(0);
4793
+ }
4794
+ }
4795
+
4796
+ .dp__panel--sheet .dp__cal-day {
4797
+ height: var(--hit-touch);
4798
+ }
4799
+
4800
+ .dp__panel--sheet .dp__cal-day .day-num {
4801
+ width: 40px;
4802
+ height: 40px;
4803
+ font-size: 15px;
4804
+ }
4805
+
4806
+ .dp__panel--sheet .dp__cal-nav,
4807
+ .dp__panel--sheet .dp__back {
4808
+ width: var(--hit-touch);
4809
+ height: var(--hit-touch);
4810
+ }
4811
+
4812
+ .dp__panel--sheet .dp__cal-pick,
4813
+ .dp__panel--sheet .dp__cal-cell,
4814
+ .dp__panel--sheet .dp__preset,
4815
+ .dp__panel--sheet .dp__actions .btn {
4816
+ min-height: var(--hit-touch);
4817
+ }
4818
+
4819
+ /* 16px stops iOS Safari zooming the page when the input takes focus. */
4820
+ .dp__panel--sheet .dp__field input {
4821
+ min-height: var(--hit-touch);
4822
+ font-size: 16px;
4823
+ }
4824
+
4825
+ @media (prefers-reduced-motion: reduce) {
4826
+ .dp__panel.dp__panel--sheet {
4827
+ animation: none;
4828
+ }
4829
+ }
4830
+
4705
4831
  /* ── TOUCH TARGET TIER ──────────────────────────────────────────────
4706
4832
  The design system documents three tiers: --hit-base 40px for forms,
4707
4833
  --hit-touch 48px for touch, --hit-pos 64px for the till. Until now
@@ -4876,6 +5002,28 @@ input.ef-input[type='number'] {
4876
5002
  }
4877
5003
  }
4878
5004
 
5005
+ /* A keepInView action is the screen's next step (confirm, prepare, ...): on a
5006
+ phone it keeps its word beside the icon. Icons alone could not tell
5007
+ "Confirmer" (pi-check) from "Livrer" (pi-check-circle). Declared after the
5008
+ two rules above that hide toolbar labels and square the buttons, because
5009
+ a media query adds no specificity. */
5010
+ @media (max-width: 767px) {
5011
+ .detail-toolbar .right .btn.btn--keep-label > span {
5012
+ display: inline;
5013
+ }
5014
+
5015
+ .detail-toolbar .right .btn.btn--keep-label {
5016
+ padding: 7px 14px;
5017
+ }
5018
+ }
5019
+
5020
+ @media (pointer: coarse) and (max-width: 767px) {
5021
+ .detail-toolbar .right .btn.btn--keep-label {
5022
+ inline-size: auto;
5023
+ padding: 0 16px;
5024
+ }
5025
+ }
5026
+
4879
5027
  /* The toolbar's overflow trigger is the shared row-actions kebab. Inside
4880
5028
  the toolbar it is a real 48px target (not the table's overhang trick,
4881
5029
  which needs a row to reserve the margin), and a flex item that may not
@@ -4976,3 +5124,145 @@ input.ef-input[type='number'] {
4976
5124
  padding-block-end: calc(env(safe-area-inset-bottom, 0px) + 20px + var(--ef-order-fab-h) + var(--s-3));
4977
5125
  }
4978
5126
  }
5127
+
5128
+ /* .f-more ("More filters") on a touch device: reaches the 48px touch target.
5129
+ By pointer rather than width, like the other touch rules. Last in the file
5130
+ so the base .f-more min-height does not win. The row aligns its items to
5131
+ center, so the pills beside it keep their own height. */
5132
+ @media (pointer: coarse) {
5133
+ .f-pill,
5134
+ .f-more,
5135
+ .f-clear {
5136
+ min-height: var(--hit-touch);
5137
+ }
5138
+ }
5139
+
5140
+ /* ── Touch tier, wave 2 (QA D2, D4, D7) ──────────────────────────────
5141
+ A thumb needs 48px; these four controls were left at their desktop
5142
+ height. By pointer, like the rules above, so a mouse keeps the dense
5143
+ layout. Last in the file so the base rules do not win. */
5144
+ @media (pointer: coarse) {
5145
+ /* The ⋮ overflow menu and the shared row-actions menu: 36px items. */
5146
+ .row-actions__item,
5147
+ .ef-menu__item {
5148
+ min-height: var(--hit-touch);
5149
+ }
5150
+
5151
+ /* Confirm dialog actions ("Annuler" / "Recharger"): 40px. */
5152
+ .es-confirm .p-confirmdialog-accept-button,
5153
+ .es-confirm .p-confirmdialog-reject-button {
5154
+ min-height: var(--hit-touch);
5155
+ }
5156
+
5157
+ /* Dialog header close: a 32px ghost circle. */
5158
+ .es-dialog .p-dialog-header-icon,
5159
+ .es-dialog .p-dialog-close-button,
5160
+ .es-dialog .es-dialog__close {
5161
+ width: var(--hit-touch);
5162
+ height: var(--hit-touch);
5163
+ }
5164
+ }
5165
+
5166
+ /* ef-pdf-preview footer on a phone: five actions in one row clipped every
5167
+ label. Let them wrap to two rows of equal-width buttons; Close, which
5168
+ pushed itself to the leading edge on a wide footer, joins the grid.
5169
+ Breakpoint is the shell's 767px (EfViewportService). */
5170
+ @media (max-width: 767px) {
5171
+ .es-dialog.ef-pdf-preview-dialog .p-dialog-footer {
5172
+ flex-wrap: wrap;
5173
+ }
5174
+
5175
+ .es-dialog.ef-pdf-preview-dialog .p-dialog-footer .btn {
5176
+ flex: 1 1 calc(50% - var(--s-2));
5177
+ min-width: 0;
5178
+ justify-content: center;
5179
+ }
5180
+
5181
+ .es-dialog.ef-pdf-preview-dialog .p-dialog-footer .btn-dialog-leading {
5182
+ margin-inline-end: 0;
5183
+ }
5184
+ }
5185
+
5186
+ /* A Latin code (order reference, SKU) inside RTL text keeps its own
5187
+ left-to-right order and is not reordered by its neighbours. Without it
5188
+ the card's reference clipped at the wrong end in Arabic. The isolate is
5189
+ a no-op in LTR. */
5190
+ .tbl .ref,
5191
+ .mrow__primary .ref {
5192
+ direction: ltr;
5193
+ unicode-bidi: isolate;
5194
+ }
5195
+
5196
+ .mrow__primary .ref {
5197
+ display: inline-block;
5198
+ max-width: 100%;
5199
+ overflow: hidden;
5200
+ text-overflow: ellipsis;
5201
+ vertical-align: bottom;
5202
+ }
5203
+
5204
+ /* ──────────── EF-PASSWORD — COMPTOIR VARIANT ────────────────────────
5205
+ `<ef-password variant="comptoir">` puts `.ef-password--comptoir` on the
5206
+ p-password root. Same box as `.ef-input` (--hit-field: 40px, 48px on a
5207
+ coarse pointer), and the show/hide toggle is a --hit-field square. */
5208
+ .ef-password--comptoir.p-password {
5209
+ position: relative;
5210
+ display: block;
5211
+ width: 100%;
5212
+ }
5213
+
5214
+ .ef-password--comptoir.p-password .p-password-input {
5215
+ font: inherit;
5216
+ font-size: 14px;
5217
+ line-height: 1.2;
5218
+ box-sizing: border-box;
5219
+ width: 100%;
5220
+ height: var(--hit-field);
5221
+ padding-block: 0;
5222
+ padding-inline: 12px;
5223
+ background: var(--paper-alt);
5224
+ border: 1px solid var(--rule);
5225
+ border-radius: var(--r-md);
5226
+ color: var(--text);
5227
+ box-shadow: none;
5228
+ outline: 0;
5229
+ transition:
5230
+ border-color var(--t-fast) var(--ease-out),
5231
+ box-shadow var(--t-fast) var(--ease-out);
5232
+ }
5233
+
5234
+ .ef-password--comptoir.p-password .p-password-input:focus {
5235
+ border-color: var(--tenant-400);
5236
+ box-shadow: 0 0 0 4px var(--tenant-100);
5237
+ }
5238
+
5239
+ .ef-password--comptoir.p-password .p-password-input:disabled {
5240
+ background: var(--paper);
5241
+ color: var(--text-mute);
5242
+ cursor: not-allowed;
5243
+ }
5244
+
5245
+ .ef-password--comptoir.p-password.ng-invalid.ng-touched .p-password-input {
5246
+ border-color: var(--st-cancelled-fg);
5247
+ box-shadow: 0 0 0 3px var(--st-cancelled-bg);
5248
+ }
5249
+
5250
+ /* Room for the toggle, on whichever side the text ends. */
5251
+ .ef-password--comptoir.p-password:has(.p-password-toggle-mask-icon) .p-password-input {
5252
+ padding-inline-end: var(--hit-field);
5253
+ }
5254
+
5255
+ /* The 16px glyph sits in a --hit-field square (padding grows the target,
5256
+ not the glyph) pinned to the input's end edge. */
5257
+ .ef-password--comptoir.p-password .p-password-toggle-mask-icon {
5258
+ position: absolute;
5259
+ inset-block-start: 0;
5260
+ inset-inline-end: 0;
5261
+ margin: 0;
5262
+ box-sizing: border-box;
5263
+ width: var(--hit-field);
5264
+ height: var(--hit-field);
5265
+ padding: calc((var(--hit-field) - 16px) / 2);
5266
+ color: var(--text-mute);
5267
+ cursor: pointer;
5268
+ }