@foxeltech/angular-ui 0.2.0 → 0.3.0

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.
Files changed (38) hide show
  1. package/components.css +2 -17
  2. package/fesm2022/foxeltech-angular-ui.mjs +343 -77
  3. package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
  4. package/index.d.ts +123 -34
  5. package/package.json +4 -5
  6. package/src/lib/styles/components.css +2 -17
  7. package/src/lib/styles/tailwind.css +11 -8
  8. package/src/lib/styles/tokens.css +131 -0
  9. package/src/lib/styles/utilities.css +24 -0
  10. package/src/lib/ui/components/button/button.component.html +4 -1
  11. package/src/lib/ui/components/checkbox/checkbox.component.html +3 -2
  12. package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +3 -2
  13. package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +3 -0
  14. package/src/lib/ui/components/drawer/drawer.component.html +3 -0
  15. package/src/lib/ui/components/drawer/drawer.component.scss +3 -0
  16. package/src/lib/ui/components/input/input.component.html +15 -3
  17. package/src/lib/ui/components/kanban-board/kanban-board.component.scss +3 -0
  18. package/src/lib/ui/components/master-detail/master-detail.component.css +11 -0
  19. package/src/lib/ui/components/master-detail/master-detail.component.html +70 -0
  20. package/src/lib/ui/components/meter/meter.component.html +8 -1
  21. package/src/lib/ui/components/radio-button/radio-button.component.html +10 -4
  22. package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +8 -3
  23. package/src/lib/ui/components/rich-text-area/rich-text-area.component.scss +3 -0
  24. package/src/lib/ui/components/select/select.component.html +9 -4
  25. package/src/lib/ui/components/severity-badges/severity-badges.component.html +5 -4
  26. package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +2 -2
  27. package/src/lib/ui/components/slider/slider.component.html +3 -0
  28. package/src/lib/ui/components/switch/switch.component.html +11 -6
  29. package/src/lib/ui/components/tab-group/tab-group.component.html +15 -1
  30. package/src/lib/ui/components/tab-group/tab-group.component.scss +3 -0
  31. package/src/lib/ui/components/tag/tag.component.html +6 -1
  32. package/src/lib/ui/components/toast/toast.component.html +2 -1
  33. package/src/lib/ui/dialogs/confirmation/confirmation.component.html +1 -1
  34. package/tailwind.css +11 -8
  35. package/tokens.css +131 -0
  36. package/utilities.css +24 -0
  37. package/tailwind-config.d.ts +0 -4
  38. package/tailwind.config.js +0 -113
package/index.d.ts CHANGED
@@ -1,46 +1,46 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { OnDestroy, Injector, DestroyRef, ApplicationRef, OnInit, AfterViewInit, ChangeDetectorRef, Type, EventEmitter, Provider, ModuleWithProviders, TemplateRef, ViewContainerRef, ElementRef, RendererFactory2, OnChanges, SimpleChanges, AfterContentInit, QueryList, Renderer2, NgZone } from '@angular/core';
3
3
  import * as _foxeltech_angular_ui from '@foxeltech/angular-ui';
4
- import * as i52 from '@angular/material/paginator';
4
+ import * as i53 from '@angular/material/paginator';
5
5
  import { MatPaginator } from '@angular/material/paginator';
6
- import * as i53 from '@angular/material/table';
6
+ import * as i54 from '@angular/material/table';
7
7
  import { MatTableDataSource, MatTable } from '@angular/material/table';
8
8
  import { HttpClient, HttpEvent, HttpErrorResponse, HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
9
9
  import * as rxjs from 'rxjs';
10
10
  import { Observable, Subject } from 'rxjs';
11
- import * as i39 from '@angular/forms';
11
+ import * as i40 from '@angular/forms';
12
12
  import { NgForm, ValidationErrors, NgControl, ControlValueAccessor } from '@angular/forms';
13
- import * as i55 from '@angular/material/dialog';
13
+ import * as i56 from '@angular/material/dialog';
14
14
  import { MatDialogRef, MatDialog } from '@angular/material/dialog';
15
- import * as i40 from '@angular/router';
15
+ import * as i41 from '@angular/router';
16
16
  import { ActivatedRouteSnapshot, RouterStateSnapshot, ResolveFn, CanActivate, Router } from '@angular/router';
17
17
  import { TranslateHttpLoader } from '@ngx-translate/http-loader';
18
18
  import * as i1 from '@ngx-translate/core';
19
19
  import { TranslateService } from '@ngx-translate/core';
20
20
  import { EChartsOption, ECharts } from 'echarts';
21
- import * as i46 from 'ngx-vflow';
21
+ import * as i47 from 'ngx-vflow';
22
22
  import { Node, Edge, Connection } from 'ngx-vflow';
23
- import * as i65 from '@angular/cdk/drag-drop';
23
+ import * as i66 from '@angular/cdk/drag-drop';
24
24
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
25
- import * as i38 from '@angular/common';
26
- import * as i41 from '@danielmoncada/angular-datetime-picker';
27
- import * as i42 from '@danielmoncada/angular-datetime-picker-moment-adapter';
28
- import * as i45 from '@dimaslz/ng-heroicons';
29
- import * as i47 from 'ngx-echarts';
30
- import * as i48 from '@angular/material/select';
31
- import * as i49 from '@angular/material/radio';
32
- import * as i50 from '@angular/material/button';
33
- import * as i51 from '@angular/material/icon';
34
- import * as i54 from '@angular/material/snack-bar';
35
- import * as i56 from '@angular/material/checkbox';
36
- import * as i57 from '@angular/material/card';
37
- import * as i58 from '@angular/material/datepicker';
38
- import * as i59 from '@angular/material/timepicker';
39
- import * as i60 from '@angular/material/badge';
40
- import * as i61 from '@angular/material/expansion';
41
- import * as i62 from '@angular/material/form-field';
42
- import * as i63 from '@angular/material/menu';
43
- import * as i64 from '@angular/material/tooltip';
25
+ import * as i39 from '@angular/common';
26
+ import * as i42 from '@danielmoncada/angular-datetime-picker';
27
+ import * as i43 from '@danielmoncada/angular-datetime-picker-moment-adapter';
28
+ import * as i46 from '@dimaslz/ng-heroicons';
29
+ import * as i48 from 'ngx-echarts';
30
+ import * as i49 from '@angular/material/select';
31
+ import * as i50 from '@angular/material/radio';
32
+ import * as i51 from '@angular/material/button';
33
+ import * as i52 from '@angular/material/icon';
34
+ import * as i55 from '@angular/material/snack-bar';
35
+ import * as i57 from '@angular/material/checkbox';
36
+ import * as i58 from '@angular/material/card';
37
+ import * as i59 from '@angular/material/datepicker';
38
+ import * as i60 from '@angular/material/timepicker';
39
+ import * as i61 from '@angular/material/badge';
40
+ import * as i62 from '@angular/material/expansion';
41
+ import * as i63 from '@angular/material/form-field';
42
+ import * as i64 from '@angular/material/menu';
43
+ import * as i65 from '@angular/material/tooltip';
44
44
 
45
45
  declare abstract class BaseComponent implements OnDestroy {
46
46
  protected injector: Injector;
@@ -131,6 +131,7 @@ declare class BaseTableComponent<T = any> extends BaseComponent implements OnIni
131
131
  create?: {
132
132
  dialog?: Type<{}>;
133
133
  size?: string;
134
+ disableClose?: boolean;
134
135
  label?: string;
135
136
  title?: string;
136
137
  message?: string;
@@ -138,6 +139,7 @@ declare class BaseTableComponent<T = any> extends BaseComponent implements OnIni
138
139
  update?: {
139
140
  dialog?: Type<{}>;
140
141
  size?: string;
142
+ disableClose?: boolean;
141
143
  label?: string;
142
144
  title?: string;
143
145
  message?: string;
@@ -145,6 +147,7 @@ declare class BaseTableComponent<T = any> extends BaseComponent implements OnIni
145
147
  view?: {
146
148
  dialog?: Type<{}>;
147
149
  size?: string;
150
+ disableClose?: boolean;
148
151
  label?: string;
149
152
  title?: string;
150
153
  message?: string;
@@ -201,6 +204,40 @@ declare class BaseTableComponent<T = any> extends BaseComponent implements OnIni
201
204
  static ɵdir: i0.ɵɵDirectiveDeclaration<BaseTableComponent<any>, never, never, {}, {}, never, never, true, never>;
202
205
  }
203
206
 
207
+ /**
208
+ * List + detail-pane counterpart of BaseTableComponent: the page keeps a
209
+ * selectable row list on one side and a lazily fetched, per-id-cached detail
210
+ * on the other. Pair it with `<fx-ui-master-detail>` which renders the
211
+ * two-column shell from this state.
212
+ *
213
+ * Subclasses declare where ids and details come from:
214
+ * protected override idKey = 'licenseId';
215
+ * protected override detailUrl(id: string) { return `/license/${id}`; }
216
+ * `detailUrl` returning null (the default) means the selected row itself is
217
+ * the detail and no request is made.
218
+ */
219
+ declare class BaseMasterDetailComponent<T = any> extends BaseTableComponent<T> {
220
+ selectedId: string | null;
221
+ selected: T | null;
222
+ detailMap: Map<string, any>;
223
+ detailLoading: Set<string>;
224
+ constructor(injector: Injector, api: HttpWrapper, modal: any, ref: ChangeDetectorRef);
225
+ /** Key the row id is read from. Override idOf() instead for composite ids. */
226
+ protected idKey: string;
227
+ idOf(row: any): string | null;
228
+ protected detailUrl(id: string): string | null;
229
+ /** What the detail pane shows: the fetched detail when cached, else the row. */
230
+ get detail(): any;
231
+ get detailBusy(): boolean;
232
+ setDataSource(result: any): void;
233
+ /** Keep the previous selection when it survived the new page, else pick row 0. */
234
+ autoSelectFirst(): void;
235
+ selectItem(row: T): void;
236
+ fetchDetail(id: string): void;
237
+ static ɵfac: i0.ɵɵFactoryDeclaration<BaseMasterDetailComponent<any>, never>;
238
+ static ɵdir: i0.ɵɵDirectiveDeclaration<BaseMasterDetailComponent<any>, never, never, {}, {}, never, never, true, never>;
239
+ }
240
+
204
241
  declare class BaseDialogComponent<T = any> extends BaseComponent implements AfterViewInit, OnInit {
205
242
  ref: MatDialogRef<any>;
206
243
  bindings: any;
@@ -508,9 +545,9 @@ declare class FxUtils {
508
545
  * helpers return `null` for "no meaningful value" and the `toneText` /
509
546
  * `toneBg` / `toneBadge` wrappers fall back to a neutral class.
510
547
  *
511
- * The emitted Tailwind utilities are guaranteed by the safelist in the shared
512
- * tailwind preset (tailwind.config.js) do not rely on content scanning for
513
- * these dynamic strings.
548
+ * Every emitted utility must appear below as a WHOLE literal string — the
549
+ * Tailwind content scanner (v4 has no safelist) only sees complete class
550
+ * names. Never rebuild these with string interpolation.
514
551
  */
515
552
  type Tone = 'critical' | 'danger' | 'warning' | 'success' | 'information';
516
553
  /** Severity / risk-level string → tone (Critical & High → danger, Medium → warning, Low → success). */
@@ -784,6 +821,9 @@ declare class InputComponent extends FxComponent<string> implements AfterViewIni
784
821
  blurred: EventEmitter<void>;
785
822
  focused: EventEmitter<void>;
786
823
  suffixClick: EventEmitter<void>;
824
+ /** Accessible name for the suffix icon button (it renders no text). */
825
+ suffixAriaLabel: string;
826
+ readonly fieldId: string;
787
827
  showPassword: boolean;
788
828
  validateError: ValidationErrors | null;
789
829
  constructor(ref: ChangeDetectorRef);
@@ -796,7 +836,7 @@ declare class InputComponent extends FxComponent<string> implements AfterViewIni
796
836
  onSuffixClick(): void;
797
837
  get displayType(): string;
798
838
  static ɵfac: i0.ɵɵFactoryDeclaration<InputComponent, never>;
799
- static ɵcmp: i0.ɵɵComponentDeclaration<InputComponent, "fx-ui-input", never, { "label": { "alias": "label"; "required": false; }; "tooltip": { "alias": "tooltip"; "required": false; }; "type": { "alias": "type"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "errorMessages": { "alias": "errorMessages"; "required": false; }; "required": { "alias": "required"; "required": false; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; }; "class": { "alias": "class"; "required": false; }; "maxlength": { "alias": "maxlength"; "required": false; }; "validateFn": { "alias": "validateFn"; "required": false; }; }, { "blurred": "blurred"; "focused": "focused"; "suffixClick": "suffixClick"; }, never, never, false, never>;
839
+ static ɵcmp: i0.ɵɵComponentDeclaration<InputComponent, "fx-ui-input", never, { "label": { "alias": "label"; "required": false; }; "tooltip": { "alias": "tooltip"; "required": false; }; "type": { "alias": "type"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "errorMessages": { "alias": "errorMessages"; "required": false; }; "required": { "alias": "required"; "required": false; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; }; "class": { "alias": "class"; "required": false; }; "maxlength": { "alias": "maxlength"; "required": false; }; "validateFn": { "alias": "validateFn"; "required": false; }; "suffixAriaLabel": { "alias": "suffixAriaLabel"; "required": false; }; }, { "blurred": "blurred"; "focused": "focused"; "suffixClick": "suffixClick"; }, never, never, false, never>;
800
840
  }
801
841
 
802
842
  declare class SelectComponent extends FxComponent<string | string[]> implements AfterViewInit, OnInit, OnChanges {
@@ -819,6 +859,7 @@ declare class SelectComponent extends FxComponent<string | string[]> implements
819
859
  }[]>;
820
860
  /** Emits the current value when the select panel closes (useful for multiple mode). */
821
861
  closed: EventEmitter<string | string[]>;
862
+ readonly fieldId: string;
822
863
  searchTerm: string;
823
864
  filteredOptions: {
824
865
  label: string;
@@ -848,6 +889,7 @@ interface IRadioButton {
848
889
  }
849
890
  declare class RadioButtonComponent extends FxComponent<IRadioButton> implements AfterViewInit {
850
891
  private ref;
892
+ readonly groupId: string;
851
893
  label?: string;
852
894
  tooltip: string;
853
895
  required?: boolean;
@@ -926,14 +968,19 @@ declare class ButtonComponent {
926
968
  icon?: any;
927
969
  class?: any;
928
970
  loading: boolean;
971
+ /** Native button type. Defaults to 'button' so it never implicitly submits a form. */
972
+ type: 'button' | 'submit' | 'reset';
973
+ /** Accessible name for icon-only usage (icon set, no label). */
974
+ ariaLabel: string;
929
975
  clicked: EventEmitter<void>;
930
976
  onClick(): void;
931
977
  static ɵfac: i0.ɵɵFactoryDeclaration<ButtonComponent, never>;
932
- static ɵcmp: i0.ɵɵComponentDeclaration<ButtonComponent, "fx-ui-button", never, { "label": { "alias": "label"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "buttonVariant": { "alias": "buttonVariant"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "class": { "alias": "class"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; }, { "clicked": "clicked"; }, never, never, false, never>;
978
+ static ɵcmp: i0.ɵɵComponentDeclaration<ButtonComponent, "fx-ui-button", never, { "label": { "alias": "label"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "buttonVariant": { "alias": "buttonVariant"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "class": { "alias": "class"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "type": { "alias": "type"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; }; }, { "clicked": "clicked"; }, never, never, false, never>;
933
979
  }
934
980
 
935
981
  declare class RadioButtonToggleComponent extends FxComponent<any> implements AfterViewInit {
936
982
  private ref;
983
+ readonly groupId: string;
937
984
  label?: string;
938
985
  required?: boolean;
939
986
  options: {
@@ -960,6 +1007,7 @@ declare class DatetimePicker extends FxComponent<any> implements AfterViewInit {
960
1007
  maxDate?: any;
961
1008
  errorMessages: ErrorMessages;
962
1009
  validateFn: (date: string) => ValidationErrors | null;
1010
+ readonly fieldId: string;
963
1011
  startAt: any;
964
1012
  constructor(ref: ChangeDetectorRef);
965
1013
  ngAfterViewInit(): void;
@@ -1014,6 +1062,8 @@ declare class TabGroupComponent implements AfterContentInit {
1014
1062
  constructor(renderer: Renderer2);
1015
1063
  ngAfterContentInit(): void;
1016
1064
  selectTab(index: number): void;
1065
+ /** Roving tablist keyboard nav: arrows move AND activate (selection follows focus). */
1066
+ onTabKeydown(event: KeyboardEvent, index: number): void;
1017
1067
  private updateUnderlinePosition;
1018
1068
  private scrollToActiveTab;
1019
1069
  scroll(direction: 'left' | 'right'): void;
@@ -1157,12 +1207,14 @@ declare class SliderComponent extends FxComponent<any> implements AfterViewInit
1157
1207
  declare class SwitchComponent extends FxComponent<any> implements AfterViewInit {
1158
1208
  private cdr;
1159
1209
  onSwitch: EventEmitter<boolean>;
1210
+ /** Accessible name — the switch renders no visible text of its own. */
1211
+ ariaLabel: string;
1160
1212
  ngAfterViewInit(): void;
1161
1213
  constructor(cdr: ChangeDetectorRef);
1162
1214
  writeValue(value: any): void;
1163
1215
  toggle(): void;
1164
1216
  static ɵfac: i0.ɵɵFactoryDeclaration<SwitchComponent, never>;
1165
- static ɵcmp: i0.ɵɵComponentDeclaration<SwitchComponent, "fx-ui-switch", never, {}, { "onSwitch": "onSwitch"; }, never, never, false, never>;
1217
+ static ɵcmp: i0.ɵɵComponentDeclaration<SwitchComponent, "fx-ui-switch", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; }; }, { "onSwitch": "onSwitch"; }, never, never, false, never>;
1166
1218
  }
1167
1219
 
1168
1220
  declare class RichTextAreaComponent extends FxComponent<any> implements AfterViewInit {
@@ -1463,6 +1515,43 @@ declare class SeverityBadgesComponent {
1463
1515
  static ɵcmp: i0.ɵɵComponentDeclaration<SeverityBadgesComponent, "fx-ui-severity-badges", never, { "stats": { "alias": "stats"; "required": false; }; "showZero": { "alias": "showZero"; "required": false; }; "suffixed": { "alias": "suffixed"; "required": false; }; }, { "badgeClick": "badgeClick"; }, never, never, false, never>;
1464
1516
  }
1465
1517
 
1518
+ /**
1519
+ * Two-column master-detail shell driven by a BaseMasterDetailComponent.
1520
+ * The host page projects its own header/filters and supplies templates for
1521
+ * the parts that vary per entity:
1522
+ *
1523
+ * <fx-ui-master-detail [table]="this" [emptyMessage]="'noData' | translate">
1524
+ * <div mdHeader>…title / stat cards…</div>
1525
+ * <div mdFilters>…search bar / filter chips…</div>
1526
+ * <ng-template #row let-item let-selected="selected">…row body…</ng-template>
1527
+ * <ng-template #detail let-detail>…detail pane…</ng-template>
1528
+ * </fx-ui-master-detail>
1529
+ *
1530
+ * The list behaves as a single-select listbox: the selected option is the
1531
+ * tab stop, ArrowUp/Down/Home/End move the selection.
1532
+ */
1533
+ declare class MasterDetailComponent implements AfterViewInit {
1534
+ table: BaseMasterDetailComponent<any>;
1535
+ /** Fixed list-pane width on lg+ viewports (stacked full-width below). */
1536
+ listWidth: string;
1537
+ maxListHeight: string;
1538
+ pageSizeOptions: number[];
1539
+ /** Labels come in via inputs — the lib carries no i18n. */
1540
+ emptyMessage: string;
1541
+ listLabel: string;
1542
+ skeletonCards: number;
1543
+ rowTemplate: TemplateRef<any>;
1544
+ detailTemplate: TemplateRef<any>;
1545
+ paginator: MatPaginator;
1546
+ readonly uid: string;
1547
+ ngAfterViewInit(): void;
1548
+ isSelected(row: any): boolean;
1549
+ optionId(index: number): string;
1550
+ onKeydown(event: KeyboardEvent, index: number): void;
1551
+ static ɵfac: i0.ɵɵFactoryDeclaration<MasterDetailComponent, never>;
1552
+ static ɵcmp: i0.ɵɵComponentDeclaration<MasterDetailComponent, "fx-ui-master-detail", never, { "table": { "alias": "table"; "required": false; }; "listWidth": { "alias": "listWidth"; "required": false; }; "maxListHeight": { "alias": "maxListHeight"; "required": false; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; }; "listLabel": { "alias": "listLabel"; "required": false; }; "skeletonCards": { "alias": "skeletonCards"; "required": false; }; }, {}, ["rowTemplate", "detailTemplate"], ["[mdHeader]", "[mdFilters]"], false, never>;
1553
+ }
1554
+
1466
1555
  declare class ConfirmationDialogComponent {
1467
1556
  private ref;
1468
1557
  bindings: any;
@@ -1489,9 +1578,9 @@ declare const MY_MOMENT_FORMATS: {
1489
1578
  };
1490
1579
  declare class UiModule {
1491
1580
  static ɵfac: i0.ɵɵFactoryDeclaration<UiModule, never>;
1492
- static ɵmod: i0.ɵɵNgModuleDeclaration<UiModule, [typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof ChartComponent, typeof SliderComponent, typeof SwitchComponent, typeof RichTextAreaComponent, typeof SkeletonTableLoadingComponent, typeof FlowConnection, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof ConfirmationDialogComponent], [typeof i38.CommonModule, typeof i39.FormsModule, typeof i39.ReactiveFormsModule, typeof i40.RouterModule, typeof i41.OwlDateTimeModule, typeof i41.OwlNativeDateTimeModule, typeof i42.OwlMomentDateTimeModule, typeof HasPermissionDirective, typeof TrimOnBlurDirective, typeof i45.NgHeroiconsModule, typeof i46.VflowComponent, typeof i46.HandleComponent, typeof i46.ResizableComponent, typeof i46.SelectableDirective, typeof i46.MiniMapComponent, typeof i46.NodeToolbarComponent, typeof i46.CustomTemplateEdgeComponent, typeof i46.DragHandleDirective, typeof i46.ConnectionControllerDirective, typeof i46.NodeHtmlTemplateDirective, typeof i46.NodeSvgTemplateDirective, typeof i46.GroupNodeTemplateDirective, typeof i46.EdgeLabelHtmlTemplateDirective, typeof i46.EdgeTemplateDirective, typeof i46.ConnectionTemplateDirective, typeof i46.HandleTemplateDirective, typeof i47.NgxEchartsModule, typeof i48.MatSelectModule, typeof i49.MatRadioModule, typeof i50.MatButtonModule, typeof i51.MatIconModule, typeof i52.MatPaginatorModule, typeof i53.MatTableModule, typeof i54.MatSnackBarModule, typeof i55.MatDialogModule, typeof i56.MatCheckboxModule, typeof i57.MatCardModule, typeof i58.MatDatepickerModule, typeof i59.MatTimepickerModule, typeof i60.MatBadgeModule, typeof i61.MatExpansionModule, typeof i62.MatFormFieldModule, typeof i63.MatMenuModule, typeof i64.MatTooltipModule, typeof i65.DragDropModule], [typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof ChartComponent, typeof SliderComponent, typeof SwitchComponent, typeof RichTextAreaComponent, typeof SkeletonTableLoadingComponent, typeof FlowConnection, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof ConfirmationDialogComponent, typeof i39.FormsModule, typeof i39.ReactiveFormsModule, typeof i40.RouterModule, typeof i41.OwlDateTimeModule, typeof i41.OwlNativeDateTimeModule, typeof HasPermissionDirective, typeof i45.NgHeroiconsModule, typeof i48.MatSelectModule, typeof i49.MatRadioModule, typeof i50.MatButtonModule, typeof i51.MatIconModule, typeof i52.MatPaginatorModule, typeof i53.MatTableModule, typeof i54.MatSnackBarModule, typeof i55.MatDialogModule, typeof i56.MatCheckboxModule, typeof i57.MatCardModule, typeof i58.MatDatepickerModule, typeof i59.MatTimepickerModule, typeof i60.MatBadgeModule, typeof i61.MatExpansionModule, typeof i62.MatFormFieldModule, typeof i63.MatMenuModule, typeof i64.MatTooltipModule, typeof i65.DragDropModule]>;
1581
+ static ɵmod: i0.ɵɵNgModuleDeclaration<UiModule, [typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof ChartComponent, typeof SliderComponent, typeof SwitchComponent, typeof RichTextAreaComponent, typeof SkeletonTableLoadingComponent, typeof FlowConnection, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof MasterDetailComponent, typeof ConfirmationDialogComponent], [typeof i39.CommonModule, typeof i40.FormsModule, typeof i40.ReactiveFormsModule, typeof i41.RouterModule, typeof i42.OwlDateTimeModule, typeof i42.OwlNativeDateTimeModule, typeof i43.OwlMomentDateTimeModule, typeof HasPermissionDirective, typeof TrimOnBlurDirective, typeof i46.NgHeroiconsModule, typeof i47.VflowComponent, typeof i47.HandleComponent, typeof i47.ResizableComponent, typeof i47.SelectableDirective, typeof i47.MiniMapComponent, typeof i47.NodeToolbarComponent, typeof i47.CustomTemplateEdgeComponent, typeof i47.DragHandleDirective, typeof i47.ConnectionControllerDirective, typeof i47.NodeHtmlTemplateDirective, typeof i47.NodeSvgTemplateDirective, typeof i47.GroupNodeTemplateDirective, typeof i47.EdgeLabelHtmlTemplateDirective, typeof i47.EdgeTemplateDirective, typeof i47.ConnectionTemplateDirective, typeof i47.HandleTemplateDirective, typeof i48.NgxEchartsModule, typeof i49.MatSelectModule, typeof i50.MatRadioModule, typeof i51.MatButtonModule, typeof i52.MatIconModule, typeof i53.MatPaginatorModule, typeof i54.MatTableModule, typeof i55.MatSnackBarModule, typeof i56.MatDialogModule, typeof i57.MatCheckboxModule, typeof i58.MatCardModule, typeof i59.MatDatepickerModule, typeof i60.MatTimepickerModule, typeof i61.MatBadgeModule, typeof i62.MatExpansionModule, typeof i63.MatFormFieldModule, typeof i64.MatMenuModule, typeof i65.MatTooltipModule, typeof i66.DragDropModule], [typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof ChartComponent, typeof SliderComponent, typeof SwitchComponent, typeof RichTextAreaComponent, typeof SkeletonTableLoadingComponent, typeof FlowConnection, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof MasterDetailComponent, typeof ConfirmationDialogComponent, typeof i40.FormsModule, typeof i40.ReactiveFormsModule, typeof i41.RouterModule, typeof i42.OwlDateTimeModule, typeof i42.OwlNativeDateTimeModule, typeof HasPermissionDirective, typeof i46.NgHeroiconsModule, typeof i49.MatSelectModule, typeof i50.MatRadioModule, typeof i51.MatButtonModule, typeof i52.MatIconModule, typeof i53.MatPaginatorModule, typeof i54.MatTableModule, typeof i55.MatSnackBarModule, typeof i56.MatDialogModule, typeof i57.MatCheckboxModule, typeof i58.MatCardModule, typeof i59.MatDatepickerModule, typeof i60.MatTimepickerModule, typeof i61.MatBadgeModule, typeof i62.MatExpansionModule, typeof i63.MatFormFieldModule, typeof i64.MatMenuModule, typeof i65.MatTooltipModule, typeof i66.DragDropModule]>;
1493
1582
  static ɵinj: i0.ɵɵInjectorDeclaration<UiModule>;
1494
1583
  }
1495
1584
 
1496
- export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, ChartComponent, CheckboxComponent, CircleProgressBar, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, EmptyStateComponent, FilterChipsComponent, FlowConnection, FxLoadingService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InfoFieldComponent, InputComponent, KanbanBoardComponent, LoadingPanel, MY_MOMENT_FORMATS, MeterComponent, NotificationService, PermissionGuard, PermissionService, QuillStyleLoaderService, RadioButtonComponent, RadioButtonToggleComponent, RealtimeTableSync, RichTextAreaComponent, SearchBarComponent, SectionCardComponent, SelectComponent, SeverityBadgesComponent, SkeletonDetailComponent, SkeletonListComponent, SkeletonTableLoadingComponent, SliderComponent, StatCardsComponent, SwitchComponent, TabComponent, TabGroupComponent, TableCell, TagComponent, ThemeService, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, TreeDiagram, TrimOnBlurDirective, UiModule, countTone, createApi, fxListResolver, scoreTone, severityTone, toneBadge, toneBg, toneColor, toneText };
1585
+ export { AuthInterceptor, AuthStateService, BaseComponent, BaseDialogComponent, BaseMasterDetailComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, ChartComponent, CheckboxComponent, CircleProgressBar, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, EmptyStateComponent, FilterChipsComponent, FlowConnection, FxLoadingService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InfoFieldComponent, InputComponent, KanbanBoardComponent, LoadingPanel, MY_MOMENT_FORMATS, MasterDetailComponent, MeterComponent, NotificationService, PermissionGuard, PermissionService, QuillStyleLoaderService, RadioButtonComponent, RadioButtonToggleComponent, RealtimeTableSync, RichTextAreaComponent, SearchBarComponent, SectionCardComponent, SelectComponent, SeverityBadgesComponent, SkeletonDetailComponent, SkeletonListComponent, SkeletonTableLoadingComponent, SliderComponent, StatCardsComponent, SwitchComponent, TabComponent, TabGroupComponent, TableCell, TagComponent, ThemeService, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, TreeDiagram, TrimOnBlurDirective, UiModule, countTone, createApi, fxListResolver, scoreTone, severityTone, toneBadge, toneBg, toneColor, toneText };
1497
1586
  export type { Breadcrumb, ColumnChangedEvent, FxApiClass, FxFilterChipOption, FxListRequest, FxListResolverContext, FxSeverityBadge, FxStatCard, IChartType, IRadioButton, KanbanColumn, NotificationCallback, NotificationConnectOptions, RealtimeTableEvent, RealtimeTableSyncOptions, TableResult, TagType, ToastData, Tone, TreeNode, UploadResult };
package/package.json CHANGED
@@ -1,14 +1,12 @@
1
1
  {
2
2
  "name": "@foxeltech/angular-ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "peerDependencies": {
9
- "tailwindcss": "^3.0.0",
10
- "autoprefixer": "^10.0.0",
11
- "postcss": "^8.0.0",
9
+ "tailwindcss": "^4.0.0",
12
10
  "@angular/common": "^20.3.0",
13
11
  "@angular/animations": "^20.3.0",
14
12
  "@angular/core": "^20.3.0",
@@ -33,13 +31,14 @@
33
31
  "@microsoft/signalr": "^10.0.0"
34
32
  },
35
33
  "exports": {
36
- "./tailwind-config": "./tailwind.config.js",
37
34
  "./tailwind.css": "./tailwind.css",
38
35
  "./theme.css": "./theme.css",
39
36
  "./components.css": "./components.css",
40
37
  "./dialogs.css": "./dialogs.css",
41
38
  "./fonts.css": "./fonts.css",
42
39
  "./animations.css": "./animations.css",
40
+ "./tokens.css": "./tokens.css",
41
+ "./utilities.css": "./utilities.css",
43
42
  "./package.json": {
44
43
  "default": "./package.json"
45
44
  },
@@ -296,9 +296,6 @@ input[type='password'] {
296
296
  .txt-card-info-description {
297
297
  @apply text-xs font-light text-text-secondary tracking-normal;
298
298
  }
299
- .txt-tag-common {
300
- @apply font-semibold text-xs;
301
- }
302
299
  .txt-tag-default {
303
300
  @apply txt-tag-common text-text-secondary;
304
301
  }
@@ -330,9 +327,6 @@ input[type='password'] {
330
327
  @apply font-mono text-sm text-text-primary tracking-normal;
331
328
  }
332
329
 
333
- .btn-common {
334
- @apply flex text-sm h-10 font-semibold px-xl py-normal items-center justify-center rounded-lg shadow-sm transition-all duration-200 disabled:opacity-50 disabled:pointer-events-none disabled:cursor-not-allowed;
335
- }
336
330
  .btn-default {
337
331
  @apply btn-common bg-button-default hover:opacity-75 text-text-inverse;
338
332
  }
@@ -345,9 +339,6 @@ input[type='password'] {
345
339
  .btn-alternative {
346
340
  @apply btn-common hover:bg-bg-hover text-text-primary border border-border-default;
347
341
  }
348
- .btn-menu-common {
349
- @apply flex flex-row items-center px-semi;
350
- }
351
342
  .btn-menu-top {
352
343
  @apply btn-menu-common border-b border-border-default pt-small pb-semi;
353
344
  }
@@ -359,7 +350,7 @@ input[type='password'] {
359
350
  }
360
351
 
361
352
  .input-default {
362
- @apply block h-[36px] text-text-primary placeholder:text-text-placeholder bg-bg-primary w-full rounded-md border px-semi py-normal border-border-default focus:outline-none focus:border-2 focus:border-gradient-primary-start text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out;
353
+ @apply block h-[36px] text-text-primary placeholder:text-text-placeholder bg-bg-primary w-full rounded-md border px-semi py-normal border-border-default focus:outline-none focus:border-2 focus:border-gradient-primary-start focus-visible:ring-2 focus-visible:ring-primary/50 text-sm text-text-primary tracking-normal ring-0 transition-colors duration-500 ease-in-out;
363
354
  }
364
355
  .input-invalid {
365
356
  @apply border-bg-error focus:ring-bg-error focus:border-bg-error;
@@ -368,12 +359,9 @@ input[type='password'] {
368
359
  @apply focus:border-2 focus:border-border-hover2 focus:bg-bg-hover2;
369
360
  }
370
361
  .input-otp {
371
- @apply bg-bg-primary w-full rounded-md border px-semi py-normal border-border-default focus:outline-none focus:border-2 focus:border-gradient-primary-start text-text-primary ring-0 transition-colors duration-500 ease-in-out;
362
+ @apply bg-bg-primary w-full rounded-md border px-semi py-normal border-border-default focus:outline-none focus:border-2 focus:border-gradient-primary-start focus-visible:ring-2 focus-visible:ring-primary/50 text-text-primary ring-0 transition-colors duration-500 ease-in-out;
372
363
  }
373
364
 
374
- .card-common {
375
- @apply text-left px-xl py-large border border-border-default rounded-lg shadow-sm transition-colors duration-500 ease-in-out;
376
- }
377
365
  .card-information {
378
366
  @apply card-common hover:opacity-70 hover:shadow-md hover:border-border-selected;
379
367
  }
@@ -384,9 +372,6 @@ input[type='password'] {
384
372
  @apply flex items-center justify-between rounded-md px-semi py-normal bg-bg-primary mb-normal last:mb-0;
385
373
  }
386
374
 
387
- .tag-common {
388
- @apply flex min-w-7 px-[10px] py-[2px] leading-5 hover:opacity-70 items-center justify-center;
389
- }
390
375
  .tag-default {
391
376
  @apply tag-common bg-bg-hover;
392
377
  }
@@ -1,18 +1,21 @@
1
+ /* fonts.css is NOT imported here: Tailwind v4 inlines imports and rebases
2
+ font url()s against the entry file, which breaks webpack resolution.
3
+ Consumers add '@foxeltech/angular-ui/fonts.css' to their styles array. */
4
+ @import 'tailwindcss';
5
+ @import './tokens.css';
6
+ @import './utilities.css';
1
7
  @import './theme.css';
2
- @import './components.css';
3
- @import './dialogs.css';
4
- @import './fonts.css';
8
+ @import './components.css' layer(components);
9
+ @import './dialogs.css' layer(components);
5
10
  @import './animations.css';
6
11
  @import '@danielmoncada/angular-datetime-picker/assets/style/picker.min.css';
7
- @tailwind base;
8
- @tailwind components;
9
- @tailwind utilities;
10
12
 
11
- html, body {
13
+ html,
14
+ body {
12
15
  font-family: 'Roboto';
13
16
  margin: 0;
14
17
  padding: 0;
15
18
  height: 100%;
16
19
  width: 100%;
17
20
  background: rgb(var(--bg-primary));
18
- }
21
+ }
@@ -0,0 +1,131 @@
1
+ /*
2
+ * Tailwind v4 CSS-first theme for @foxeltech/angular-ui.
3
+ * Replaces the old JS preset (tailwind.config.js / lodash.merge sharing).
4
+ *
5
+ * Colour tokens point at the runtime RGB-triplet variables from theme.css
6
+ * (dark default on :root, light via .light_theme) so theme switching keeps
7
+ * working; opacity modifiers like bg-critical/10 are handled by v4's
8
+ * color-mix() and need no <alpha-value> plumbing.
9
+ */
10
+ /* `inline` is load-bearing: without it the rgb(var(--x)) values are baked
11
+ into :root once, so .light_theme's runtime triplet overrides never reach
12
+ the utilities. inline makes every utility carry rgb(var(--x)) itself and
13
+ resolve at the element that uses it — same behavior as v3. */
14
+ @theme inline {
15
+ /* Colours (names match the v3 preset so every existing class keeps working) */
16
+ --color-gradient-primary-start: rgb(var(--gradient-primary-start));
17
+ --color-gradient-primary-end: rgb(var(--gradient-primary-end));
18
+ --color-gradient-success-start: rgb(var(--gradient-success-start));
19
+ --color-gradient-success-end: rgb(var(--gradient-success-end));
20
+ --color-primary: rgb(var(--primary));
21
+ --color-success: rgb(var(--success));
22
+ --color-danger: rgb(var(--danger));
23
+ --color-warning: rgb(var(--warning));
24
+ --color-critical: rgb(var(--critical));
25
+ --color-discovery: rgb(var(--discovery));
26
+ --color-information: rgb(var(--information));
27
+ --color-bg-primary: rgb(var(--bg-primary));
28
+ --color-bg-canvas: rgb(var(--bg-canvas));
29
+ --color-bg-hover: rgb(var(--bg-primary-hover));
30
+ --color-bg-error: rgb(var(--bg-error-bold));
31
+ --color-bg-hover2: rgb(var(--bg-secondary-hover));
32
+ --color-text-primary: rgb(var(--text-primary));
33
+ --color-text-secondary: rgb(var(--text-secondary));
34
+ --color-text-placeholder: rgb(var(--text-placeholder));
35
+ --color-text-selected: rgb(var(--text-selected-primary));
36
+ --color-text-focus: rgb(var(--text-focus));
37
+ --color-text-inverse: rgb(var(--text-inverse));
38
+ --color-text-error: rgb(var(--text-error));
39
+ --color-text-link: rgb(var(--text-link-primary));
40
+ --color-border-default: rgb(var(--border-default));
41
+ --color-border-interactive: rgb(var(--border-interactive));
42
+ --color-border-selected: rgb(var(--border-selected));
43
+ --color-border-strong: rgb(var(--border-strong));
44
+ --color-border-hover2: rgb(var(--border-secondary-hover));
45
+ --color-button-default: rgb(var(--button-default));
46
+ --color-button-primary: rgb(var(--button-primary));
47
+
48
+ /* Breakpoints (v3 custom screens) */
49
+ --breakpoint-sm: 480px;
50
+ --breakpoint-md: 720px;
51
+ --breakpoint-lg: 1080px;
52
+ --breakpoint-xl: 1920px;
53
+
54
+ /* Shadows — same scale as the v3 preset, incl. the DEFAULT key so the bare
55
+ `shadow` utility keeps its v3 meaning (no shadow→shadow-sm rename sweep). */
56
+ --shadow-sm: 0 1px 2px 0 rgb(var(--shadow-color) / 0.05);
57
+ --shadow: 0 1px 3px 0 rgb(var(--shadow-color) / 0.1), 0 1px 2px -1px rgb(var(--shadow-color) / 0.1);
58
+ --shadow-md: 0 4px 6px -1px rgb(var(--shadow-color) / 0.1), 0 2px 4px -2px rgb(var(--shadow-color) / 0.1);
59
+ --shadow-lg: 0 10px 15px -3px rgb(var(--shadow-color) / 0.1), 0 4px 6px -4px rgb(var(--shadow-color) / 0.1);
60
+ --shadow-xl: 0 20px 25px -5px rgb(var(--shadow-color) / 0.1), 0 10px 10px -5px rgb(var(--shadow-color) / 0.1);
61
+ --shadow-2xl: 0 25px 50px -12px rgb(var(--shadow-color) / 0.25);
62
+ --inset-shadow-sm: inset 0 2px 4px 0 rgb(var(--shadow-color) / 0.05);
63
+
64
+ /* v3 default border radii, incl. DEFAULT so bare `rounded` keeps working */
65
+ --radius-sm: 0.125rem;
66
+ --radius: 0.25rem;
67
+ --radius-md: 0.375rem;
68
+ --radius-lg: 0.5rem;
69
+ --radius-xl: 0.75rem;
70
+ --radius-2xl: 1rem;
71
+ --radius-3xl: 1.5rem;
72
+
73
+ /* Named spacing scale (gap-small, p-semi, mb-large, …) */
74
+ --spacing-xs: 0.125rem;
75
+ --spacing-small: 0.25rem;
76
+ --spacing-normal: 0.5rem;
77
+ --spacing-semi: 0.75rem;
78
+ --spacing-large: 1rem;
79
+ --spacing-xl: 1.25rem;
80
+ --spacing-2xl: 1.5rem;
81
+
82
+ /* Font families */
83
+ --font-spmono: 'SpaceMonoRegular', monospace;
84
+ --font-dmsans: 'DMSans', sans-serif;
85
+ --font-orbitron: 'Orbitron', sans-serif;
86
+ --font-bevn: 'BeVietnamPro', sans-serif;
87
+ --font-roboto: 'Roboto', sans-serif;
88
+
89
+ /* Font-size overrides (v3 preset values) */
90
+ --text-xs: 0.75rem;
91
+ --text-sm: 0.875rem;
92
+ --text-base: 1rem;
93
+ --text-xl: 1.25rem;
94
+ --text-2xl: 1.625rem;
95
+ --text-3xl: 2rem;
96
+ --text-4xl: 2.25rem;
97
+ --text-5xl: 3rem;
98
+ }
99
+
100
+ /* v3 backgroundImage entries — v4 has no background-image theme namespace */
101
+ @utility bg-gradient-primary {
102
+ background-image: linear-gradient(
103
+ 135deg,
104
+ rgb(var(--gradient-primary-start)) 0%,
105
+ rgb(var(--gradient-primary-end)) 100%
106
+ );
107
+ }
108
+ @utility bg-gradient-success {
109
+ background-image: linear-gradient(
110
+ 135deg,
111
+ rgb(var(--gradient-success-start)) 0%,
112
+ rgb(var(--gradient-success-end)) 100%
113
+ );
114
+ }
115
+
116
+ /* v3 behavior compat (per the official upgrade guide) */
117
+ @layer base {
118
+ /* v4 defaults borders to currentColor; restore the theme default */
119
+ *,
120
+ ::after,
121
+ ::before,
122
+ ::backdrop,
123
+ ::file-selector-button {
124
+ border-color: rgb(var(--border-default));
125
+ }
126
+ /* v4 preflight switched buttons to cursor: default */
127
+ button:not(:disabled),
128
+ [role='button']:not(:disabled) {
129
+ cursor: pointer;
130
+ }
131
+ }
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Shared composable utilities (v4 @utility) — kept OUT of components.css
3
+ * because that file is imported inside layer(components) and @utility must
4
+ * be top-level/unlayered. Usable both in markup and via @apply.
5
+ */
6
+ @utility txt-tag-common {
7
+ @apply font-semibold text-xs;
8
+ }
9
+
10
+ @utility btn-common {
11
+ @apply flex text-sm h-10 font-semibold px-xl py-normal items-center justify-center rounded-lg shadow-sm transition-all duration-200 disabled:opacity-50 disabled:pointer-events-none disabled:cursor-not-allowed;
12
+ }
13
+
14
+ @utility btn-menu-common {
15
+ @apply flex flex-row items-center px-semi;
16
+ }
17
+
18
+ @utility card-common {
19
+ @apply text-left px-xl py-large border border-border-default rounded-lg shadow-sm transition-colors duration-500 ease-in-out;
20
+ }
21
+
22
+ @utility tag-common {
23
+ @apply flex min-w-7 px-[10px] py-[2px] leading-5 hover:opacity-70 items-center justify-center;
24
+ }
@@ -1,4 +1,7 @@
1
1
  <button
2
+ [attr.type]="type"
3
+ [attr.aria-label]="ariaLabel || null"
4
+ [attr.aria-busy]="loading || null"
2
5
  [class]="class"
3
6
  [ngClass]="{
4
7
  'btn-default': buttonVariant === 'default',
@@ -10,7 +13,7 @@
10
13
  (click)="onClick()"
11
14
  >
12
15
  @if (loading) {
13
- <div class="flex w-full items-center justify-center">
16
+ <div class="flex w-full items-center justify-center" aria-hidden="true">
14
17
  <svg
15
18
  [attr.fill]="
16
19
  buttonVariant !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'
@@ -3,16 +3,17 @@
3
3
  [class.opacity-50]="disabled"
4
4
  [class.cursor-not-allowed]="disabled"
5
5
  >
6
+ <!-- sr-only (not `hidden`): keeps the input focusable and in the a11y tree -->
6
7
  <input
7
8
  type="checkbox"
8
- class="hidden"
9
+ class="peer sr-only"
9
10
  [checked]="value"
10
11
  [disabled]="disabled"
11
12
  (change)="onInputChange($event)"
12
13
  (blur)="onTouched()"
13
14
  />
14
15
  <span
15
- class="relative w-4 h-4 border rounded-full transition-colors duration-150 shrink-0"
16
+ class="relative w-4 h-4 border rounded-full transition-colors duration-150 shrink-0 peer-focus-visible:ring-2 peer-focus-visible:ring-primary/50"
16
17
  [ngClass]="{
17
18
  'rounded-full': rounded,
18
19
  'rounded-sm': !rounded,