@gravionlabs/helix-ui 22.2.7 → 22.2.8

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": "@gravionlabs/helix-ui",
3
- "version": "22.2.7",
3
+ "version": "22.2.8",
4
4
  "description": "Helix UI: vanilla Angular components on the Helix design tokens — plain CSS, no runtime styling engine.",
5
5
  "license": "MIT",
6
6
  "keywords": [
package/styles.css CHANGED
@@ -1773,6 +1773,63 @@
1773
1773
  justify-content: flex-end;
1774
1774
  }
1775
1775
 
1776
+ /* the filter button of filterDisplay="menu": an icon button beside the label, marked when the column is filtered */
1777
+ .hx-data-table-filter-button {
1778
+ display: inline-flex;
1779
+ flex: none;
1780
+ align-items: center;
1781
+ margin: 0;
1782
+ position: relative;
1783
+ padding: 0.125rem;
1784
+ border: 0;
1785
+ background: transparent;
1786
+ color: var(--h-datatable-sort-icon-color);
1787
+ cursor: pointer;
1788
+ border-radius: 2px;
1789
+ outline-color: transparent;
1790
+ }
1791
+
1792
+ .hx-data-table-filter-icon {
1793
+ display: inline-block;
1794
+ flex: none;
1795
+ width: var(--h-datatable-sort-icon-size);
1796
+ height: var(--h-datatable-sort-icon-size);
1797
+ background: currentcolor;
1798
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5h16l-6 7.5V19l-4 1.5v-8L4 5Z'/%3E%3C/svg%3E") center/contain no-repeat;
1799
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5h16l-6 7.5V19l-4 1.5v-8L4 5Z'/%3E%3C/svg%3E") center/contain no-repeat;
1800
+ }
1801
+
1802
+ .hx-data-table-filter-button:hover {
1803
+ color: var(--h-datatable-sort-icon-hover-color);
1804
+ }
1805
+
1806
+ .hx-data-table-filter-button:focus-visible {
1807
+ outline: var(--h-datatable-header-cell-focus-ring-width) var(--h-datatable-header-cell-focus-ring-style) var(--h-datatable-header-cell-focus-ring-color);
1808
+ outline-offset: var(--h-datatable-header-cell-focus-ring-offset);
1809
+ box-shadow: var(--h-datatable-header-cell-focus-ring-shadow);
1810
+ }
1811
+
1812
+ .hx-data-table-filter-button.hx-data-table-filter-active {
1813
+ color: var(--h-datatable-header-cell-selected-color);
1814
+ }
1815
+
1816
+ .hx-data-table-filter-button.hx-data-table-filter-active::after {
1817
+ content: "";
1818
+ position: absolute;
1819
+ top: 0;
1820
+ right: 0;
1821
+ width: 0.375rem;
1822
+ height: 0.375rem;
1823
+ border-radius: 50%;
1824
+ background: currentcolor;
1825
+ }
1826
+
1827
+ .hx-data-table-filter-menu {
1828
+ display: flex;
1829
+ align-items: center;
1830
+ gap: var(--h-datatable-header-cell-gap);
1831
+ }
1832
+
1776
1833
  /* sortable headers: a button that fills the header cell */
1777
1834
  .hx-data-table-sort {
1778
1835
  display: inline-flex;
@@ -1,7 +1,7 @@
1
1
  import * as i1 from "@angular/cdk/accordion";
2
2
  import { CdkAccordionItem } from "@angular/cdk/accordion";
3
3
  import * as i0 from "@angular/core";
4
- import { EnvironmentProviders, InjectionToken, OnInit, TemplateRef, Type } from "@angular/core";
4
+ import { ElementRef, EnvironmentProviders, InjectionToken, OnInit, TemplateRef, Type } from "@angular/core";
5
5
  import { ConnectedOverlayPositionChange, ConnectedPosition } from "@angular/cdk/overlay";
6
6
  import { ControlValueAccessor } from "@angular/forms";
7
7
  import { FormValueControl } from "@angular/forms/signals";
@@ -1182,6 +1182,98 @@ export declare class HxPaginator {
1182
1182
  "pageChange": "pageChange";
1183
1183
  }, never, never, true, never>;
1184
1184
  }
1185
+ /**
1186
+ * A small panel anchored to an element, with arbitrary content and an arrow pointing at the element.
1187
+ *
1188
+ * ```html
1189
+ * <button hx-button aria-haspopup="dialog" (click)="op.toggle($event)">Share</button>
1190
+ * <hx-popover #op ariaLabel="Share this page">
1191
+ * <input hx-input aria-label="Link" value="https://…" />
1192
+ * </hx-popover>
1193
+ * ```
1194
+ *
1195
+ * `toggle(event, target?)`, `show(event, target?)` and `hide()` open it below the element of the event (or `target`),
1196
+ * or above when there is no room. An outside click and Escape close it. It is a non-modal `role="dialog"`: the focus
1197
+ * moves to its first control when it has one and returns to the element that opened it when it closes, and the page
1198
+ * behind stays reachable. Name it with `ariaLabel` or `ariaLabelledBy`, and put `aria-haspopup="dialog"` on the
1199
+ * trigger. Projected content is created with the popover, only shown while it is open.
1200
+ */
1201
+ export declare class HxPopover {
1202
+ #private;
1203
+ private readonly panel;
1204
+ /** Accessible name of the popover. */
1205
+ readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
1206
+ readonly ariaLabelledBy: import("@angular/core").InputSignal<string | undefined>;
1207
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string | undefined>;
1208
+ /** `alertdialog` for a question that needs an answer (the confirm popup). */
1209
+ readonly role: import("@angular/core").InputSignal<"dialog" | "alertdialog">;
1210
+ /** Extra CSS classes on the panel. */
1211
+ readonly panelClass: import("@angular/core").InputSignal<string | undefined>;
1212
+ /** A click outside closes it. */
1213
+ readonly dismissable: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1214
+ readonly closeOnEscape: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
1215
+ readonly shown: import("@angular/core").OutputEmitterRef<void>;
1216
+ readonly hidden: import("@angular/core").OutputEmitterRef<void>;
1217
+ readonly open: import("@angular/core").WritableSignal<boolean>;
1218
+ protected readonly origin: import("@angular/core").WritableSignal<Element | null>;
1219
+ protected readonly fallbackOrigin: HTMLElement;
1220
+ /** The popover is above the element (no room below). */
1221
+ protected readonly above: import("@angular/core").WritableSignal<boolean>;
1222
+ /** The popover is aligned to the end edge of the element (no room to extend to the right). */
1223
+ protected readonly end: import("@angular/core").WritableSignal<boolean>;
1224
+ protected readonly positions: ConnectedPosition[];
1225
+ /** Opens it at the element of the event (or `target`), or closes it when it is open. */
1226
+ toggle(event: Event | Element, target?: Element | null): void;
1227
+ /** Opens it at `target`, else at the element of the event; an element can be passed instead of an event. */
1228
+ show(event: Event | Element, target?: Element | null): void;
1229
+ hide(refocus?: boolean): void;
1230
+ protected onPosition(change: ConnectedOverlayPositionChange): void;
1231
+ protected onAttach(): void;
1232
+ protected onDetach(): void;
1233
+ protected onKeydown(event: KeyboardEvent): void;
1234
+ protected onOutsideClick(event: MouseEvent): void;
1235
+ static ɵfac: i0.ɵɵFactoryDeclaration<HxPopover, never>;
1236
+ static ɵcmp: i0.ɵɵComponentDeclaration<HxPopover, "hx-popover", never, {
1237
+ "ariaLabel": {
1238
+ "alias": "ariaLabel";
1239
+ "required": false;
1240
+ "isSignal": true;
1241
+ };
1242
+ "ariaLabelledBy": {
1243
+ "alias": "ariaLabelledBy";
1244
+ "required": false;
1245
+ "isSignal": true;
1246
+ };
1247
+ "ariaDescribedBy": {
1248
+ "alias": "ariaDescribedBy";
1249
+ "required": false;
1250
+ "isSignal": true;
1251
+ };
1252
+ "role": {
1253
+ "alias": "role";
1254
+ "required": false;
1255
+ "isSignal": true;
1256
+ };
1257
+ "panelClass": {
1258
+ "alias": "panelClass";
1259
+ "required": false;
1260
+ "isSignal": true;
1261
+ };
1262
+ "dismissable": {
1263
+ "alias": "dismissable";
1264
+ "required": false;
1265
+ "isSignal": true;
1266
+ };
1267
+ "closeOnEscape": {
1268
+ "alias": "closeOnEscape";
1269
+ "required": false;
1270
+ "isSignal": true;
1271
+ };
1272
+ }, {
1273
+ "shown": "shown";
1274
+ "hidden": "hidden";
1275
+ }, never, ["*"], true, never>;
1276
+ }
1185
1277
  type HxTableSize = 'small' | 'medium' | 'large';
1186
1278
  /**
1187
1279
  * A native `<table>` drawn as a Helix table (CSS only): header, body and footer rows, hover, stripes and gridlines
@@ -1258,7 +1350,7 @@ interface HxColumn {
1258
1350
  align?: HxColumnAlign;
1259
1351
  /** The header is a button that sorts by the column. */
1260
1352
  sortable?: boolean;
1261
- /** The column gets a text filter in the filter row (`filterDisplay="row"`). */
1353
+ /** The column gets a text filter: in the filter row (`filterDisplay="row"`) or in a popover from its header (`"menu"`). */
1262
1354
  filter?: boolean;
1263
1355
  /** The direction of the first click on the sort button (the table's `sortFirstOrder` by default). */
1264
1356
  sortFirstOrder?: HxSortFirstOrder;
@@ -1384,13 +1476,13 @@ interface HxTableRowContext {
1384
1476
  *
1385
1477
  * ```html
1386
1478
  * <hx-data-table [value]="invoices" [columns]="columns" dataKey="id" caption="Invoices" stripedRows>
1387
- * <ng-template hxCell="amount" let-value>{{ value | currency: 'EUR' }}</ng-template>
1479
+ * <ng-template hxCell="amount" let-value="value">{{ value | currency: 'EUR' }}</ng-template>
1388
1480
  * </hx-data-table>
1389
1481
  * ```
1390
1482
  *
1391
1483
  * The table keeps the native semantics: a `<caption>` (drawn as the table header; visually hidden when only
1392
1484
  * `ariaLabel` is set), `<th scope="col">` cells and `aria-busy` while `loading`. A scrolling table is a labelled,
1393
- * focusable `region`.
1485
+ * focusable `region`. `filterDisplay="menu"` puts the column filters in a popover opened from the header.
1394
1486
  */
1395
1487
  export declare class HxDataTable implements OnInit {
1396
1488
  /** The rows. */
@@ -1457,11 +1549,21 @@ export declare class HxDataTable implements OnInit {
1457
1549
  readonly selectRowLabel: import("@angular/core").InputSignal<string>;
1458
1550
  /** The properties of a row the global filter looks in (`filterGlobal`). */
1459
1551
  readonly globalFilterFields: import("@angular/core").InputSignal<readonly string[]>;
1460
- /** `row`: a filter row with a text input under the headers of columns with `filter: true`. */
1461
- readonly filterDisplay: import("@angular/core").InputSignal<"row" | undefined>;
1552
+ /**
1553
+ * `row`: a filter row with a text input under the headers of columns with `filter: true`. `menu`: a filter button in
1554
+ * those headers that opens a popover with the text input.
1555
+ */
1556
+ readonly filterDisplay: import("@angular/core").InputSignal<"menu" | "row" | undefined>;
1462
1557
  /** The text of the column filters, by field. */
1463
1558
  readonly filters: import("@angular/core").ModelSignal<Record<string, string>>;
1464
1559
  readonly filterLabel: import("@angular/core").InputSignal<string>;
1560
+ /** The text of the button that empties a filter in the header menu. */
1561
+ readonly clearLabel: import("@angular/core").InputSignal<string>;
1562
+ protected readonly filterPopover: import("@angular/core").Signal<HxPopover | undefined>;
1563
+ protected readonly filterInput: import("@angular/core").Signal<ElementRef<HTMLInputElement> | undefined>;
1564
+ /** The column whose filter popover is open. */
1565
+ protected readonly activeFilterColumn: import("@angular/core").WritableSignal<HxColumn | null>;
1566
+ private readonly injector;
1465
1567
  /** The rows that are open (by `dataKey`, or the row index without one); needs a `hxRowExpansion` template. */
1466
1568
  readonly expandedRowKeys: import("@angular/core").ModelSignal<Record<string, boolean>>;
1467
1569
  readonly expandLabel: import("@angular/core").InputSignal<string>;
@@ -1513,6 +1615,9 @@ export declare class HxDataTable implements OnInit {
1513
1615
  protected onRowKey(row: unknown, event: Event): void;
1514
1616
  /** Filters every column in `globalFilterFields` for a text (case-insensitive, contains). */
1515
1617
  filterGlobal(text: string): void;
1618
+ protected openFilter(event: Event, column: HxColumn): void;
1619
+ protected filterLabelFor(column: HxColumn): string;
1620
+ protected clearFilter(column: HxColumn): void;
1516
1621
  protected setFilter(column: HxColumn, text: string): void;
1517
1622
  protected rowKey(row: unknown, index: number): string;
1518
1623
  protected isExpanded(row: unknown, index: number): boolean;
@@ -1727,6 +1832,11 @@ export declare class HxDataTable implements OnInit {
1727
1832
  "required": false;
1728
1833
  "isSignal": true;
1729
1834
  };
1835
+ "clearLabel": {
1836
+ "alias": "clearLabel";
1837
+ "required": false;
1838
+ "isSignal": true;
1839
+ };
1730
1840
  "expandedRowKeys": {
1731
1841
  "alias": "expandedRowKeys";
1732
1842
  "required": false;
@@ -4827,98 +4937,6 @@ export declare class HxPassword implements ControlValueAccessor, FormValueContro
4827
4937
  "touch": "touch";
4828
4938
  }, never, never, true, never>;
4829
4939
  }
4830
- /**
4831
- * A small panel anchored to an element, with arbitrary content and an arrow pointing at the element.
4832
- *
4833
- * ```html
4834
- * <button hx-button aria-haspopup="dialog" (click)="op.toggle($event)">Share</button>
4835
- * <hx-popover #op ariaLabel="Share this page">
4836
- * <input hx-input aria-label="Link" value="https://…" />
4837
- * </hx-popover>
4838
- * ```
4839
- *
4840
- * `toggle(event, target?)`, `show(event, target?)` and `hide()` open it below the element of the event (or `target`),
4841
- * or above when there is no room. An outside click and Escape close it. It is a non-modal `role="dialog"`: the focus
4842
- * moves to its first control when it has one and returns to the element that opened it when it closes, and the page
4843
- * behind stays reachable. Name it with `ariaLabel` or `ariaLabelledBy`, and put `aria-haspopup="dialog"` on the
4844
- * trigger. Projected content is created with the popover, only shown while it is open.
4845
- */
4846
- export declare class HxPopover {
4847
- #private;
4848
- private readonly panel;
4849
- /** Accessible name of the popover. */
4850
- readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
4851
- readonly ariaLabelledBy: import("@angular/core").InputSignal<string | undefined>;
4852
- readonly ariaDescribedBy: import("@angular/core").InputSignal<string | undefined>;
4853
- /** `alertdialog` for a question that needs an answer (the confirm popup). */
4854
- readonly role: import("@angular/core").InputSignal<"dialog" | "alertdialog">;
4855
- /** Extra CSS classes on the panel. */
4856
- readonly panelClass: import("@angular/core").InputSignal<string | undefined>;
4857
- /** A click outside closes it. */
4858
- readonly dismissable: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
4859
- readonly closeOnEscape: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
4860
- readonly shown: import("@angular/core").OutputEmitterRef<void>;
4861
- readonly hidden: import("@angular/core").OutputEmitterRef<void>;
4862
- readonly open: import("@angular/core").WritableSignal<boolean>;
4863
- protected readonly origin: import("@angular/core").WritableSignal<Element | null>;
4864
- protected readonly fallbackOrigin: HTMLElement;
4865
- /** The popover is above the element (no room below). */
4866
- protected readonly above: import("@angular/core").WritableSignal<boolean>;
4867
- /** The popover is aligned to the end edge of the element (no room to extend to the right). */
4868
- protected readonly end: import("@angular/core").WritableSignal<boolean>;
4869
- protected readonly positions: ConnectedPosition[];
4870
- /** Opens it at the element of the event (or `target`), or closes it when it is open. */
4871
- toggle(event: Event | Element, target?: Element | null): void;
4872
- /** Opens it at `target`, else at the element of the event; an element can be passed instead of an event. */
4873
- show(event: Event | Element, target?: Element | null): void;
4874
- hide(refocus?: boolean): void;
4875
- protected onPosition(change: ConnectedOverlayPositionChange): void;
4876
- protected onAttach(): void;
4877
- protected onDetach(): void;
4878
- protected onKeydown(event: KeyboardEvent): void;
4879
- protected onOutsideClick(event: MouseEvent): void;
4880
- static ɵfac: i0.ɵɵFactoryDeclaration<HxPopover, never>;
4881
- static ɵcmp: i0.ɵɵComponentDeclaration<HxPopover, "hx-popover", never, {
4882
- "ariaLabel": {
4883
- "alias": "ariaLabel";
4884
- "required": false;
4885
- "isSignal": true;
4886
- };
4887
- "ariaLabelledBy": {
4888
- "alias": "ariaLabelledBy";
4889
- "required": false;
4890
- "isSignal": true;
4891
- };
4892
- "ariaDescribedBy": {
4893
- "alias": "ariaDescribedBy";
4894
- "required": false;
4895
- "isSignal": true;
4896
- };
4897
- "role": {
4898
- "alias": "role";
4899
- "required": false;
4900
- "isSignal": true;
4901
- };
4902
- "panelClass": {
4903
- "alias": "panelClass";
4904
- "required": false;
4905
- "isSignal": true;
4906
- };
4907
- "dismissable": {
4908
- "alias": "dismissable";
4909
- "required": false;
4910
- "isSignal": true;
4911
- };
4912
- "closeOnEscape": {
4913
- "alias": "closeOnEscape";
4914
- "required": false;
4915
- "isSignal": true;
4916
- };
4917
- }, {
4918
- "shown": "shown";
4919
- "hidden": "hidden";
4920
- }, never, ["*"], true, never>;
4921
- }
4922
4940
  type HxProgressMode = 'determinate' | 'indeterminate';
4923
4941
  /**
4924
4942
  * A bar that fills from 0 to 100, or slides while the duration is unknown.