@elasticias/ui 1.0.29 → 1.0.31

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.29",
3
+ "version": "1.0.31",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.0.0",
6
6
  "@angular/core": "^21.0.0",
@@ -119,6 +119,37 @@
119
119
  --text-soft: var(--ink-400);
120
120
  --ink-active: var(--ink-900);
121
121
 
122
+ /* `--ink-soft` is not a ramp step and was never defined anywhere; it is an
123
+ alias, added because eight call sites across three files already name it
124
+ as `var(--ink-soft, #64748b)`. Undefined, every one of them fell through
125
+ to that literal, which does not flip with the theme and measures 3.46:1
126
+ on `--paper-alt` in dark. Two of those call sites sit in a `.ts` and in
127
+ another component sheet, so one definition here is the only fix that
128
+ reaches them all; it also makes the hardcoded fallback dead.
129
+ Resolves to 4.82:1 (light) / 6.63:1 (dark) on `--paper-alt`. */
130
+ --ink-soft: var(--text-mute);
131
+
132
+ /* Foreground for anything painted on the tenant accent.
133
+
134
+ `setTenantAccent()` writes the ramp onto `documentElement.style` at
135
+ runtime, so `--tenant-500` can be any hue at any lightness. A hardcoded
136
+ `#fff` fails on a light accent, and `var(--paper)` fails differently:
137
+ paper flips with the theme while the accent does not, which is how the
138
+ avatar ended up at 2.04:1 on the default maroon in dark mode.
139
+
140
+ So: black or white, whichever the accent's own lightness calls for.
141
+ Choosing the better of those two against *any* background is guaranteed
142
+ to clear AA. White scores 1.05/(Y+0.05) and black scores (Y+0.05)/0.05,
143
+ and the two are equal only at Y = 0.179, where both land on 4.58:1. The
144
+ OKLCH lightness matching that luminance is 0.623, so the clamp collapses
145
+ to 1 (white) below it and 0 (black) above it; `* -infinity` is what
146
+ forces a pure 0 or 1 instead of a gradient between them.
147
+
148
+ The plain value below is the fallback for engines without relative
149
+ colour syntax; the `@supports` block after this rule is what actually
150
+ tracks the accent. */
151
+ --on-tenant: #fff;
152
+
122
153
  /* ── Spatial scale (s-1 = 4px → s-10 = 96px) ─────────────────── */
123
154
  --s-1: 4px;
124
155
  --s-2: 8px;
@@ -142,6 +173,15 @@
142
173
  }
143
174
 
144
175
  /* ── Semantic aliases (dark) — toggled by .p-dark on <html> ────── */
176
+ /* Relative colour syntax resolves `--tenant-500` at computed-value time on
177
+ <html>, the same element `setTenantAccent()` writes the accent onto, so
178
+ this tracks a runtime accent change with no JS of its own. */
179
+ @supports (color: oklch(from #000 l c h)) {
180
+ :root {
181
+ --on-tenant: oklch(from var(--tenant-500) clamp(0, calc((l - 0.623) * -infinity), 1) 0 h);
182
+ }
183
+ }
184
+
145
185
  .p-dark {
146
186
  --paper: var(--ink-900);
147
187
  --paper-alt: var(--ink-800);
@@ -303,6 +303,12 @@
303
303
 
304
304
  .avatar.tenant {
305
305
  background: var(--tenant-500);
306
+ /* `.avatar` sets `color: var(--paper)`, which is right only while the
307
+ ground flips with it: `--ink-active` does, the tenant accent does not.
308
+ On a dark page that paired near-black initials with the accent at
309
+ 2.04:1. `--on-tenant` is black or white by the accent's own lightness,
310
+ so it holds for a runtime accent instead of for this one maroon. */
311
+ color: var(--on-tenant);
306
312
  }
307
313
 
308
314
  .avatar.sm {
@@ -2286,9 +2292,15 @@
2286
2292
  }
2287
2293
 
2288
2294
  .dp__cal-day.out .day-num {
2289
- color: var(--text-soft);
2295
+ /* These are enabled buttons: the template binds `(click)="selectDay(...)"`
2296
+ with no `disabled`, so clicking a trailing 30 jumps to the next month.
2297
+ That rules out WCAG's exemption for inactive components, and
2298
+ `--text-soft` at half opacity resolved to 1.52:1 in light and 1.80:1 in
2299
+ dark. `--text-mute` at full opacity measures 4.82:1 / 6.63:1 and still
2300
+ reads as clearly secondary next to an in-month day at 18.9:1 / 15.65:1,
2301
+ which is what the de-emphasis was for. */
2302
+ color: var(--text-mute);
2290
2303
  font-weight: 500;
2291
- opacity: 0.5;
2292
2304
  }
2293
2305
 
2294
2306
  .dp__cal-day.today .day-num {
@@ -3600,7 +3612,10 @@ input.ef-input[type='number'] {
3600
3612
  padding: 0;
3601
3613
  background: transparent;
3602
3614
  border-radius: 50%;
3603
- color: var(--text-soft);
3615
+ /* The ✕ is the affordance, not decoration, so it takes the 3:1 non-text
3616
+ bar. `--text-soft` gave it 2.49:1 in light and 3.42:1 in dark; this is
3617
+ 4.82:1 / 6.63:1 on `--paper-alt`, and hover still lifts it to `--text`. */
3618
+ color: var(--text-mute);
3604
3619
  flex-shrink: 0;
3605
3620
  cursor: pointer;
3606
3621
  transition: all var(--t-fast) var(--ease-out);
@@ -3952,7 +3967,10 @@ input.ef-input[type='number'] {
3952
3967
  width: 10px;
3953
3968
  height: 10px;
3954
3969
  font-size: 10px;
3955
- color: var(--paper);
3970
+ /* The checked box is painted with the accent, so the tick lands on a ground
3971
+ that does not flip with the theme; `var(--paper)` put it at 2.04:1 in
3972
+ dark, under the 3:1 bar for a non-text glyph. */
3973
+ color: var(--on-tenant);
3956
3974
  }
3957
3975
 
3958
3976
  /* Selected check-mark for single-select (the trailing ✓) */
@@ -4365,6 +4383,9 @@ input.ef-input[type='number'] {
4365
4383
 
4366
4384
  .es-dialog .es-dialog__highlight .av.tenant {
4367
4385
  background: var(--tenant-500);
4386
+ /* Same bug as `.avatar.tenant`: `.av` sets `color: var(--paper)` and the
4387
+ accent ground does not flip with it. */
4388
+ color: var(--on-tenant);
4368
4389
  }
4369
4390
 
4370
4391
  .es-dialog .es-dialog__highlight .body {
@@ -137,9 +137,6 @@ interface OrderEntity {
137
137
  */
138
138
  interface DocumentConfig {
139
139
  documentType: 'order' | 'invoice' | 'quote';
140
- headerLabel: string;
141
- dateLabel: string;
142
- customerLabel: string;
143
140
  enableTax?: boolean;
144
141
  enableDiscount?: boolean;
145
142
  showCatalogue?: boolean;
@@ -4455,7 +4452,9 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4455
4452
  * equivalent and a tabindex to be usable, which a decorative box should
4456
4453
  * not have.
4457
4454
  */
4458
- protected onRowHeadActivate(row: unknown, index: number, event: Event): void;
4455
+ protected onRowHeadActivate(row: TRow, index: number, event: Event): void;
4456
+ /** The chevron owns expansion once the head is busy navigating. */
4457
+ protected onDisclosureToggle(row: unknown, index: number, event: Event): void;
4459
4458
  protected toggleExpanded(row: unknown, index: number): void;
4460
4459
  private rowKey;
4461
4460
  /**
@@ -4490,6 +4489,10 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4490
4489
  /** Fields a collapsed card shows. A row shows none until it opens. */
4491
4490
  protected readonly cardPreviewColumns: _angular_core.Signal<EfDataCardColumn[]>;
4492
4491
  protected readonly hasDetail: _angular_core.Signal<boolean>;
4492
+ /** Whether the screen wired an open-the-record action to this table. */
4493
+ protected readonly rowNavigable: _angular_core.Signal<boolean>;
4494
+ /** The head is a control when it either opens the row or expands it. */
4495
+ protected readonly headIsControl: _angular_core.Signal<boolean>;
4493
4496
  /** Only worth a toggle when opening actually reveals something. */
4494
4497
  protected readonly hasMoreThanPreview: _angular_core.Signal<boolean>;
4495
4498
  /** Fields visible for a row right now, given layout and open state. */
@@ -4523,9 +4526,12 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4523
4526
  * state in the body.
4524
4527
  *
4525
4528
  * It is the *trigger*, not the copy: screens set it from
4526
- * `err?.message`, which is whatever the HTTP layer threw. The body
4527
- * state words itself from translated keys instead, so a failed list
4528
- * never shows an operator a status line or an exception string.
4529
+ * `err?.message`, which is whatever the HTTP layer threw. Neither the
4530
+ * chip nor the body state prints it — both word themselves from
4531
+ * translated keys, so a failed list never shows an operator a status
4532
+ * line or an exception string. The raw value is kept on the chip's
4533
+ * `data-error` attribute, which devtools can read and no reader can
4534
+ * see.
4529
4535
  */
4530
4536
  readonly errorMsg: _angular_core.InputSignal<string>;
4531
4537
  readonly loadingKey: _angular_core.InputSignal<string>;
@@ -4773,9 +4779,39 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4773
4779
  * popup can escape its rounded edges. */
4774
4780
  readonly openMenuCount: _angular_core.WritableSignal<number>;
4775
4781
  onRowActionsToggle(event: Event): void;
4776
- /** Fires `rowDoubleClick` unless the dblclick originated on an
4777
- * interactive child (checkbox, button, link, form control). */
4778
- onRowDoubleClick(row: TRow, event: MouseEvent): void;
4782
+ /**
4783
+ * Children that own their own click. Opening the row on top of them would
4784
+ * run two things from one gesture.
4785
+ */
4786
+ private static readonly INTERACTIVE_CHILD;
4787
+ /**
4788
+ * Bounded by the row on purpose. The row itself is given `role="button"`
4789
+ * when it is openable, so an unbounded `closest()` matches the row as its
4790
+ * own ancestor and suppresses every click on it — the interaction looks
4791
+ * wired and does nothing. Only a control *inside* the row counts.
4792
+ */
4793
+ private isInteractiveTarget;
4794
+ /**
4795
+ * A drag that selects text ends in a click. Opening the row on that click
4796
+ * throws the selection away at the instant it was made, which is worse
4797
+ * than not opening, because the work is lost rather than merely delayed.
4798
+ */
4799
+ private hasTextSelection;
4800
+ /**
4801
+ * Open a row with one click.
4802
+ *
4803
+ * This used to take two. The tell was not the pointer but the keyboard:
4804
+ * Enter on a focused row already opened it with a single press, because a
4805
+ * keyboard cannot produce a double-click at all. So the component was
4806
+ * already committed to single activation and only the mouse was asking
4807
+ * twice — and the row paints `cursor: pointer` the whole time, which says
4808
+ * a click does something.
4809
+ *
4810
+ * The output is still named `rowDoubleClick` so the twelve screens bound
4811
+ * to it keep working untouched. The name is now wrong; renaming it is a
4812
+ * breaking change to a published component and belongs in its own commit.
4813
+ */
4814
+ onRowClick(row: TRow, event: MouseEvent): void;
4779
4815
  /**
4780
4816
  * `aria-sort` for the header cell: the only thing that tells a screen
4781
4817
  * reader which column is ordered and which way. The arrow glyph is