@foxeltech/angular-ui 0.2.0 → 0.3.1

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 (41) hide show
  1. package/components.css +2 -17
  2. package/fesm2022/foxeltech-angular-ui.mjs +509 -243
  3. package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
  4. package/package.json +15 -15
  5. package/src/lib/styles/components.css +2 -17
  6. package/src/lib/styles/tailwind.css +11 -8
  7. package/src/lib/styles/tokens.css +131 -0
  8. package/src/lib/styles/utilities.css +24 -0
  9. package/src/lib/ui/components/button/button.component.html +4 -1
  10. package/src/lib/ui/components/checkbox/checkbox.component.html +3 -2
  11. package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +10 -5
  12. package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +3 -0
  13. package/src/lib/ui/components/drawer/drawer.component.html +78 -61
  14. package/src/lib/ui/components/drawer/drawer.component.scss +3 -0
  15. package/src/lib/ui/components/input/input.component.html +15 -3
  16. package/src/lib/ui/components/kanban-board/kanban-board.component.scss +3 -0
  17. package/src/lib/ui/components/loading-panel/loading-panel.component.html +53 -53
  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 +33 -27
  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/search-bar/search-bar.component.html +11 -10
  25. package/src/lib/ui/components/select/select.component.html +17 -10
  26. package/src/lib/ui/components/severity-badges/severity-badges.component.html +5 -4
  27. package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +2 -2
  28. package/src/lib/ui/components/slider/slider.component.html +20 -15
  29. package/src/lib/ui/components/switch/switch.component.html +11 -6
  30. package/src/lib/ui/components/tab-group/tab-group.component.html +44 -27
  31. package/src/lib/ui/components/tab-group/tab-group.component.scss +3 -0
  32. package/src/lib/ui/components/tag/tag.component.html +6 -1
  33. package/src/lib/ui/components/toast/toast.component.html +38 -35
  34. package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +21 -19
  35. package/src/lib/ui/dialogs/confirmation/confirmation.component.html +1 -1
  36. package/tailwind.css +11 -8
  37. package/tokens.css +131 -0
  38. package/{index.d.ts → types/foxeltech-angular-ui.d.ts} +123 -34
  39. package/utilities.css +24 -0
  40. package/tailwind-config.d.ts +0 -4
  41. package/tailwind.config.js +0 -113
@@ -3,52 +3,63 @@
3
3
  <button
4
4
  class="left-scroll-button"
5
5
  type="button"
6
+ aria-label="Scroll tabs left"
6
7
  (click)="scroll('left')"
7
8
  [style.opacity]="canScrollLeft ? 1 : 0"
8
9
  [style.pointerEvents]="canScrollLeft ? 'auto' : 'none'"
9
- >
10
+ [attr.tabindex]="canScrollLeft ? null : -1"
11
+ [attr.aria-hidden]="!canScrollLeft"
12
+ >
10
13
  <svg
14
+ aria-hidden="true"
11
15
  xmlns="http://www.w3.org/2000/svg"
12
16
  class="h-5 w-5 text-text-primary"
13
17
  fill="none"
14
18
  viewBox="0 0 24 24"
15
19
  stroke="currentColor"
16
- >
20
+ >
17
21
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
18
22
  </svg>
19
23
  </button>
20
24
 
21
25
  <div
22
26
  #tabList
27
+ role="tablist"
23
28
  class="relative flex overflow-x-auto no-scrollbar scroll-smooth"
24
29
  (scroll)="onScroll()"
25
- >
26
- <button
27
- *ngFor="let tab of tabs.toArray(); let i = index"
28
- (click)="selectTab(i)"
29
- class="tab-btn tab-bar-btn"
30
30
  >
31
- <div class="flex flex-row items-center justify-center">
32
- @if (tab.icon) {
33
- <fx-ui-hero-icon
34
- [icon]="tab.icon"
35
- [size]="20"
36
- class="flex mr-[2px]"
31
+ @for (tab of tabs.toArray(); track tab; let i = $index) {
32
+ <button
33
+ type="button"
34
+ role="tab"
35
+ [attr.aria-selected]="i === activeIndex"
36
+ [tabindex]="i === activeIndex ? 0 : -1"
37
+ (click)="selectTab(i)"
38
+ (keydown)="onTabKeydown($event, i)"
39
+ class="tab-btn tab-bar-btn"
40
+ >
41
+ <div class="flex flex-row items-center justify-center">
42
+ @if (tab.icon) {
43
+ <fx-ui-hero-icon
44
+ [icon]="tab.icon"
45
+ [size]="20"
46
+ class="flex mr-[2px]"
37
47
  [ngClass]="{
38
48
  'text-gradient-primary-start mb-small': i === activeIndex,
39
49
  'text-text-placeholder': i !== activeIndex,
40
50
  }"
41
- ></fx-ui-hero-icon>
42
- }
43
- <div
51
+ ></fx-ui-hero-icon>
52
+ }
53
+ <div
44
54
  [ngClass]="
45
55
  i === activeIndex ? 'txt-field-label text-gradient-primary-start' : 'txt-placeholder'
46
56
  "
47
- >
48
- {{ tab.label }}
57
+ >
58
+ {{ tab.label }}
59
+ </div>
49
60
  </div>
50
- </div>
51
- </button>
61
+ </button>
62
+ }
52
63
 
53
64
  <span #underline class="underline" style="width: 0; transform: translateX(0)"></span>
54
65
  </div>
@@ -56,17 +67,21 @@
56
67
  <button
57
68
  class="right-scroll-button"
58
69
  type="button"
70
+ aria-label="Scroll tabs right"
59
71
  (click)="scroll('right')"
60
72
  [style.opacity]="canScrollRight ? 1 : 0"
61
73
  [style.pointerEvents]="canScrollRight ? 'auto' : 'none'"
62
- >
74
+ [attr.tabindex]="canScrollRight ? null : -1"
75
+ [attr.aria-hidden]="!canScrollRight"
76
+ >
63
77
  <svg
78
+ aria-hidden="true"
64
79
  xmlns="http://www.w3.org/2000/svg"
65
80
  class="h-5 w-5 text-text-primary"
66
81
  fill="none"
67
82
  viewBox="0 0 24 24"
68
83
  stroke="currentColor"
69
- >
84
+ >
70
85
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
71
86
  </svg>
72
87
  </button>
@@ -74,9 +89,11 @@
74
89
 
75
90
  <!-- Tab content -->
76
91
  <div class="transition-all duration-300 ease-in-out mt-4">
77
- <ng-container *ngFor="let tab of tabs.toArray(); let i = index">
78
- <div *ngIf="i === activeIndex" class="animate-fadeIn">
79
- <ng-container *ngTemplateOutlet="tab.content"></ng-container>
80
- </div>
81
- </ng-container>
92
+ @for (tab of tabs.toArray(); track tab; let i = $index) {
93
+ @if (i === activeIndex) {
94
+ <div role="tabpanel" class="animate-fadeIn">
95
+ <ng-container *ngTemplateOutlet="tab.content"></ng-container>
96
+ </div>
97
+ }
98
+ }
82
99
  </div>
@@ -1,3 +1,6 @@
1
+ /* Tailwind v4: component styles compile in isolation — @reference pulls in the theme for @apply without re-emitting it. */
2
+ @reference '../../../styles/tailwind.css';
3
+
1
4
  @keyframes fadeIn {
2
5
  from {
3
6
  opacity: 0;
@@ -1,7 +1,12 @@
1
+ <!-- Interactive semantics only when a (clicked) listener is attached. -->
1
2
  <div
2
3
  (click)="onClick()"
4
+ (keydown.enter)="onClick()"
5
+ (keydown.space)="$event.preventDefault(); onClick()"
6
+ [attr.role]="clicked.observed ? 'button' : null"
7
+ [attr.tabindex]="clicked.observed ? 0 : null"
3
8
  [class]="
4
- `flex flex-row gap-small ${rounded ? 'tag-round' : 'tag-square'} tag-${type}${solid ? '-solid' : ''}`
9
+ `flex flex-row gap-small ${rounded ? 'tag-round' : 'tag-square'} tag-${type}${solid ? '-solid' : ''}${clicked.observed ? ' cursor-pointer focus-visible:ring-2 focus-visible:ring-primary/50' : ''}`
5
10
  "
6
11
  >
7
12
  @if (icon) {
@@ -1,6 +1,7 @@
1
1
  <div
2
2
  animate.enter="horizontal-fade-in-animation"
3
3
  animate.leave="horizontal-fade-out-animation"
4
+ [attr.role]="type === 'error' ? 'alert' : 'status'"
4
5
  class="flex border-l-[3px] items-center bg-bg-primary gap-semi min-w-[250px] max-w-[400px] px-large py-semi rounded shadow-lg transition-all duration-300 ease-in-out transform opacity-100 translate-y-0"
5
6
  [ngClass]="{
6
7
  'border-success': type === 'success',
@@ -8,41 +9,43 @@
8
9
  'border-warning': type === 'warning',
9
10
  'border-information': type === 'info'
10
11
  }"
11
- >
12
- <div class="">
12
+ >
13
+ <div class="" aria-hidden="true">
13
14
  @switch (type) { @case('success') {
14
- <fx-ui-hero-icon
15
- icon="check-circle"
16
- [solid]="true"
17
- [size]="30"
18
- class="text-success"
19
- ></fx-ui-hero-icon>
20
- } @case('error') {
21
- <fx-ui-hero-icon
22
- icon="exclamation-circle"
23
- [solid]="true"
24
- [size]="30"
25
- class="text-critical"
26
- ></fx-ui-hero-icon>
27
- } @case('warning') {
28
- <fx-ui-hero-icon
29
- icon="exclamation-triangle"
30
- [solid]="true"
31
- [size]="30"
32
- class="text-warning"
33
- ></fx-ui-hero-icon>
34
- } @default {
35
- <fx-ui-hero-icon
36
- icon="information-circle"
37
- [solid]="true"
38
- [size]="30"
39
- class="text-information"
40
- ></fx-ui-hero-icon>
41
- } }
42
- </div>
15
+ <fx-ui-hero-icon
16
+ icon="check-circle"
17
+ [solid]="true"
18
+ [size]="30"
19
+ class="text-success"
20
+ ></fx-ui-hero-icon>
21
+ } @case('error') {
22
+ <fx-ui-hero-icon
23
+ icon="exclamation-circle"
24
+ [solid]="true"
25
+ [size]="30"
26
+ class="text-critical"
27
+ ></fx-ui-hero-icon>
28
+ } @case('warning') {
29
+ <fx-ui-hero-icon
30
+ icon="exclamation-triangle"
31
+ [solid]="true"
32
+ [size]="30"
33
+ class="text-warning"
34
+ ></fx-ui-hero-icon>
35
+ } @default {
36
+ <fx-ui-hero-icon
37
+ icon="information-circle"
38
+ [solid]="true"
39
+ [size]="30"
40
+ class="text-information"
41
+ ></fx-ui-hero-icon>
42
+ } }
43
+ </div>
43
44
 
44
- <div class="flex flex-col">
45
- <strong *ngIf="title" class="txt-field-label">{{ title }}</strong>
46
- <p class="txt-default">{{ message }}</p>
45
+ <div class="flex flex-col">
46
+ @if (title) {
47
+ <strong class="txt-field-label">{{ title }}</strong>
48
+ }
49
+ <p class="txt-default">{{ message }}</p>
50
+ </div>
47
51
  </div>
48
- </div>
@@ -4,20 +4,21 @@
4
4
  <div
5
5
  #root
6
6
  class="mx-auto w-fit bg-blue-600 text-white px-7 py-3 rounded-md font-semibold text-center"
7
- >
7
+ >
8
8
  {{ data.label }}
9
9
  </div>
10
10
 
11
11
  <!-- CHILDREN -->
12
12
  <div class="mt-16 flex justify-center gap-16">
13
- <div
14
- *ngFor="let child of data.children"
15
- #child
16
- class="w-48 bg-rose-600 text-white px-4 py-4 rounded-lg text-center"
17
- >
18
- <div class="font-semibold text-lg">{{ child.label }}</div>
19
- <div class="mt-1 text-sm opacity-90">{{ child.status }}</div>
20
- </div>
13
+ @for (child of data.children; track child) {
14
+ <div
15
+ #child
16
+ class="w-48 bg-rose-600 text-white px-4 py-4 rounded-lg text-center"
17
+ >
18
+ <div class="font-semibold text-lg">{{ child.label }}</div>
19
+ <div class="mt-1 text-sm opacity-90">{{ child.status }}</div>
20
+ </div>
21
+ }
21
22
  </div>
22
23
 
23
24
  <!-- SVG CONNECTORS -->
@@ -25,16 +26,17 @@
25
26
  class="absolute inset-0 pointer-events-none"
26
27
  [attr.width]="svgWidth"
27
28
  [attr.height]="svgHeight"
28
- >
29
- <line
30
- *ngFor="let line of lines"
31
- [attr.x1]="line.x1"
32
- [attr.y1]="line.y1"
33
- [attr.x2]="line.x2"
34
- [attr.y2]="line.y2"
35
- stroke="#1f2937"
36
- stroke-width="2"
37
- />
29
+ >
30
+ @for (line of lines; track line) {
31
+ <line
32
+ [attr.x1]="line.x1"
33
+ [attr.y1]="line.y1"
34
+ [attr.x2]="line.x2"
35
+ [attr.y2]="line.y2"
36
+ stroke="#1f2937"
37
+ stroke-width="2"
38
+ />
39
+ }
38
40
  </svg>
39
41
 
40
42
  </div>
@@ -1,5 +1,5 @@
1
1
  <div animate.enter="fade-in-animation" class="dialog-container">
2
- <h1 class="txt-heading-05 dialog-header">{{ title }}</h1>
2
+ <h1 mat-dialog-title class="txt-heading-05 dialog-header">{{ title }}</h1>
3
3
  <mat-dialog-content>
4
4
  <div class="txt-default">{{ message }}</div>
5
5
  </mat-dialog-content>
package/tailwind.css CHANGED
@@ -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
+ }
package/tokens.css ADDED
@@ -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
+ }