@elasticias/ui 1.0.28 → 1.0.30

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.28",
3
+ "version": "1.0.30",
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;
@@ -4412,6 +4409,10 @@ type EfTableDensity = 'compact' | 'default' | 'comfortable';
4412
4409
  * "nothing to fetch" and greets a waiting user with the empty
4413
4410
  * state. While loading with no rows yet it shimmers `ef-skeleton`
4414
4411
  * rows (table and mobile list alike) and flags `aria-busy`.
4412
+ * 4. **Bind `(retry)` wherever you bind `[errorMsg]`.** An empty result
4413
+ * set that came from a failed request renders the error state, not
4414
+ * the empty one, and its "try again" button is the way out. The card
4415
+ * doesn't know the query, so the screen re-runs it.
4415
4416
  *
4416
4417
  * ```html
4417
4418
  * <ef-data-card
@@ -4513,7 +4514,19 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4513
4514
  * container is flagged `aria-busy`, as `ef-card` does.
4514
4515
  */
4515
4516
  readonly loading: _angular_core.InputSignalWithTransform<boolean, unknown>;
4516
- /** Empty string = no error. Non-empty triggers an error chip in tbl-head. */
4517
+ /**
4518
+ * Empty string = no error. Non-empty triggers the error chip in
4519
+ * `tbl-head` and, when the request came back with nothing, the error
4520
+ * state in the body.
4521
+ *
4522
+ * It is the *trigger*, not the copy: screens set it from
4523
+ * `err?.message`, which is whatever the HTTP layer threw. Neither the
4524
+ * chip nor the body state prints it — both word themselves from
4525
+ * translated keys, so a failed list never shows an operator a status
4526
+ * line or an exception string. The raw value is kept on the chip's
4527
+ * `data-error` attribute, which devtools can read and no reader can
4528
+ * see.
4529
+ */
4517
4530
  readonly errorMsg: _angular_core.InputSignal<string>;
4518
4531
  readonly loadingKey: _angular_core.InputSignal<string>;
4519
4532
  /**
@@ -4525,6 +4538,18 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4525
4538
  readonly skeletonLines: _angular_core.Signal<number[]>;
4526
4539
  /** First load: nothing to show yet, so the rows are placeholders. */
4527
4540
  readonly showSkeleton: _angular_core.Signal<boolean>;
4541
+ /**
4542
+ * The request failed and brought nothing back. Without this the body
4543
+ * falls through to the empty state and tells the operator, calmly and
4544
+ * in the product's own voice, that they have no clients — a false
4545
+ * statement about their data that they may go on to act on.
4546
+ *
4547
+ * Third in the chain, after the skeleton and before the empty state:
4548
+ * a retry that is already in flight shows progress, not the error it
4549
+ * is busy clearing. Rows already on screen stay there and keep the
4550
+ * head chip as the failure signal, the way a failed refresh should.
4551
+ */
4552
+ readonly showError: _angular_core.Signal<boolean>;
4528
4553
  /**
4529
4554
  * When `true`, double-clicking anywhere on a `<tr>` emits the row
4530
4555
  * via `rowDoubleClick` and the body rows render with
@@ -4602,6 +4627,13 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4602
4627
  readonly exportRequest: _angular_core.OutputEmitterRef<EfDataCardExportRequest>;
4603
4628
  /** Raised by the empty state's "clear search" action. */
4604
4629
  readonly clearSearch: _angular_core.OutputEmitterRef<void>;
4630
+ /**
4631
+ * Raised by the error state's "try again" button. The card knows the
4632
+ * request failed but not what the request was, so the screen re-runs
4633
+ * it — typically `(retry)="search()"` on a list screen. Unbound, the
4634
+ * button is a dead control, so bind it wherever `[errorMsg]` is bound.
4635
+ */
4636
+ readonly retry: _angular_core.OutputEmitterRef<void>;
4605
4637
  private readonly bodyTemplates;
4606
4638
  private readonly headerTemplates;
4607
4639
  private readonly bodyTemplateMap;
@@ -4761,7 +4793,7 @@ declare class EfDataCardComponent<TRow = any> implements AfterContentInit {
4761
4793
  trackByRow: (_: number, row: TRow) => unknown;
4762
4794
  trackByColumn: (_: number, col: EfDataCardColumn) => string;
4763
4795
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EfDataCardComponent<any>, never>;
4764
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EfDataCardComponent<any>, "ef-data-card", never, { "mobileLayout": { "alias": "mobileLayout"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "trackByField": { "alias": "trackByField"; "required": false; "isSignal": true; }; "pageNumber": { "alias": "pageNumber"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "totalCount": { "alias": "totalCount"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "hidePager": { "alias": "hidePager"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "loadingKey": { "alias": "loadingKey"; "required": false; "isSignal": true; }; "rowDoubleClickable": { "alias": "rowDoubleClickable"; "required": false; "isSignal": true; }; "hasActionsColumn": { "alias": "hasActionsColumn"; "required": false; "isSignal": true; }; "rowActionsContext": { "alias": "rowActionsContext"; "required": false; "isSignal": true; }; "showViewAction": { "alias": "showViewAction"; "required": false; "isSignal": true; }; "showEditAction": { "alias": "showEditAction"; "required": false; "isSignal": true; }; "showDuplicateAction": { "alias": "showDuplicateAction"; "required": false; "isSignal": true; }; "showDeleteAction": { "alias": "showDeleteAction"; "required": false; "isSignal": true; }; "showDensityControl": { "alias": "showDensityControl"; "required": false; "isSignal": true; }; "showColumnPicker": { "alias": "showColumnPicker"; "required": false; "isSignal": true; }; "showExportControl": { "alias": "showExportControl"; "required": false; "isSignal": true; }; "exporting": { "alias": "exporting"; "required": false; "isSignal": true; }; "screenContext": { "alias": "screenContext"; "required": false; "isSignal": true; }; "searchTerm": { "alias": "searchTerm"; "required": false; "isSignal": true; }; "tableKey": { "alias": "tableKey"; "required": false; "isSignal": true; }; "defaultDensity": { "alias": "defaultDensity"; "required": false; "isSignal": true; }; "reorderable": { "alias": "reorderable"; "required": false; "isSignal": true; }; "fixedLayout": { "alias": "fixedLayout"; "required": false; "isSignal": true; }; }, { "pageChange": "pageChange"; "pageSizeChange": "pageSizeChange"; "sortChange": "sortChange"; "rowDoubleClick": "rowDoubleClick"; "rowAction": "rowAction"; "exportRequest": "exportRequest"; "clearSearch": "clearSearch"; "rowReorder": "rowReorder"; }, ["bodyTemplates", "headerTemplates"], ["[tbl-head-info]", "[tbl-head-actions]", "[empty-state-mobile]", "[empty-state]"], true, never>;
4796
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EfDataCardComponent<any>, "ef-data-card", never, { "mobileLayout": { "alias": "mobileLayout"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "trackByField": { "alias": "trackByField"; "required": false; "isSignal": true; }; "pageNumber": { "alias": "pageNumber"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "totalCount": { "alias": "totalCount"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "hidePager": { "alias": "hidePager"; "required": false; "isSignal": true; }; "sort": { "alias": "sort"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "errorMsg": { "alias": "errorMsg"; "required": false; "isSignal": true; }; "loadingKey": { "alias": "loadingKey"; "required": false; "isSignal": true; }; "rowDoubleClickable": { "alias": "rowDoubleClickable"; "required": false; "isSignal": true; }; "hasActionsColumn": { "alias": "hasActionsColumn"; "required": false; "isSignal": true; }; "rowActionsContext": { "alias": "rowActionsContext"; "required": false; "isSignal": true; }; "showViewAction": { "alias": "showViewAction"; "required": false; "isSignal": true; }; "showEditAction": { "alias": "showEditAction"; "required": false; "isSignal": true; }; "showDuplicateAction": { "alias": "showDuplicateAction"; "required": false; "isSignal": true; }; "showDeleteAction": { "alias": "showDeleteAction"; "required": false; "isSignal": true; }; "showDensityControl": { "alias": "showDensityControl"; "required": false; "isSignal": true; }; "showColumnPicker": { "alias": "showColumnPicker"; "required": false; "isSignal": true; }; "showExportControl": { "alias": "showExportControl"; "required": false; "isSignal": true; }; "exporting": { "alias": "exporting"; "required": false; "isSignal": true; }; "screenContext": { "alias": "screenContext"; "required": false; "isSignal": true; }; "searchTerm": { "alias": "searchTerm"; "required": false; "isSignal": true; }; "tableKey": { "alias": "tableKey"; "required": false; "isSignal": true; }; "defaultDensity": { "alias": "defaultDensity"; "required": false; "isSignal": true; }; "reorderable": { "alias": "reorderable"; "required": false; "isSignal": true; }; "fixedLayout": { "alias": "fixedLayout"; "required": false; "isSignal": true; }; }, { "pageChange": "pageChange"; "pageSizeChange": "pageSizeChange"; "sortChange": "sortChange"; "rowDoubleClick": "rowDoubleClick"; "rowAction": "rowAction"; "exportRequest": "exportRequest"; "clearSearch": "clearSearch"; "retry": "retry"; "rowReorder": "rowReorder"; }, ["bodyTemplates", "headerTemplates"], ["[tbl-head-info]", "[tbl-head-actions]", "[empty-state-mobile]", "[empty-state]"], true, never>;
4765
4797
  }
4766
4798
 
4767
4799
  /**