@foxeltech/angular-ui 0.0.14 → 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 (134) hide show
  1. package/BeVietnamPro/BeVietnamPro-Bold.woff2 +0 -0
  2. package/BeVietnamPro/BeVietnamPro-ExtraLight.woff2 +0 -0
  3. package/BeVietnamPro/BeVietnamPro-Light.woff2 +0 -0
  4. package/BeVietnamPro/BeVietnamPro-Medium.woff2 +0 -0
  5. package/BeVietnamPro/BeVietnamPro-Regular.woff2 +0 -0
  6. package/BeVietnamPro/BeVietnamPro-SemiBold.woff2 +0 -0
  7. package/BeVietnamPro/BeVietnamPro-Thin.woff2 +0 -0
  8. package/SpaceMono-Regular.woff2 +0 -0
  9. package/components.css +7 -17
  10. package/dm-sans/DMSans-Bold.woff2 +0 -0
  11. package/dm-sans/DMSans-Light.woff2 +0 -0
  12. package/dm-sans/DMSans-Medium.woff2 +0 -0
  13. package/dm-sans/DMSans-Regular.woff2 +0 -0
  14. package/dm-sans/DMSans-SemiBold.woff2 +0 -0
  15. package/dm-sans/DMSans-Thin.woff2 +0 -0
  16. package/fesm2022/foxeltech-angular-ui.mjs +1349 -285
  17. package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
  18. package/fonts.css +68 -34
  19. package/index.d.ts +624 -139
  20. package/orbitron/Orbitron-Bold.woff2 +0 -0
  21. package/orbitron/Orbitron-Medium.woff2 +0 -0
  22. package/orbitron/Orbitron-Regular.woff2 +0 -0
  23. package/orbitron/Orbitron-SemiBold.woff2 +0 -0
  24. package/package.json +9 -10
  25. package/roboto/Roboto-Black.woff2 +0 -0
  26. package/roboto/Roboto-BlackItalic.woff2 +0 -0
  27. package/roboto/Roboto-Bold.woff2 +0 -0
  28. package/roboto/Roboto-BoldCondensed.woff2 +0 -0
  29. package/roboto/Roboto-BoldCondensedItalic.woff2 +0 -0
  30. package/roboto/Roboto-BoldItalic.woff2 +0 -0
  31. package/roboto/Roboto-Condensed.woff2 +0 -0
  32. package/roboto/Roboto-CondensedItalic.woff2 +0 -0
  33. package/roboto/Roboto-Italic.woff2 +0 -0
  34. package/roboto/Roboto-Light.woff2 +0 -0
  35. package/roboto/Roboto-LightItalic.woff2 +0 -0
  36. package/roboto/Roboto-Medium.woff2 +0 -0
  37. package/roboto/Roboto-MediumItalic.woff2 +0 -0
  38. package/roboto/Roboto-Regular.woff2 +0 -0
  39. package/roboto/Roboto-Thin.woff2 +0 -0
  40. package/roboto/Roboto-ThinItalic.woff2 +0 -0
  41. package/src/lib/styles/components.css +7 -17
  42. package/src/lib/styles/fonts.css +68 -34
  43. package/src/lib/styles/tailwind.css +11 -8
  44. package/src/lib/styles/tokens.css +131 -0
  45. package/src/lib/styles/utilities.css +24 -0
  46. package/src/lib/ui/components/button/button.component.html +4 -1
  47. package/src/lib/ui/components/button/button.component.scss +0 -0
  48. package/src/lib/ui/components/chart/chart.component.scss +49 -0
  49. package/src/lib/ui/components/checkbox/checkbox.component.html +3 -2
  50. package/src/lib/ui/components/checkbox/checkbox.component.scss +0 -0
  51. package/src/lib/ui/components/circle-progress-bar/circle-progress-bar.component.scss +0 -0
  52. package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +3 -2
  53. package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +147 -0
  54. package/src/lib/ui/components/dnd-upload/dnd-upload.component.scss +87 -0
  55. package/src/lib/ui/components/drawer/drawer.component.html +3 -0
  56. package/src/lib/ui/components/drawer/drawer.component.scss +134 -0
  57. package/src/lib/ui/components/empty-state/empty-state.component.html +9 -0
  58. package/src/lib/ui/components/filter-chips/filter-chips.component.html +12 -0
  59. package/src/lib/ui/components/flow-connection/flow-connection.component.scss +0 -0
  60. package/src/lib/ui/components/hero-icon/hero-icon.component.scss +0 -0
  61. package/src/lib/ui/components/info-field/info-field.component.html +4 -0
  62. package/src/lib/ui/components/input/input.component.html +15 -3
  63. package/src/lib/ui/components/kanban-board/kanban-board.component.scss +70 -0
  64. package/src/lib/ui/components/loading-panel/loading-panel.component.scss +0 -0
  65. package/src/lib/ui/components/master-detail/master-detail.component.css +11 -0
  66. package/src/lib/ui/components/master-detail/master-detail.component.html +70 -0
  67. package/src/lib/ui/components/meter/meter.component.html +22 -0
  68. package/src/lib/ui/components/radio-button/radio-button.component.html +10 -4
  69. package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +8 -3
  70. package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.scss +0 -0
  71. package/src/lib/ui/components/rich-text-area/rich-text-area.component.scss +18 -0
  72. package/src/lib/ui/components/search-bar/search-bar.component.scss +0 -0
  73. package/src/lib/ui/components/section-card/section-card.component.html +9 -0
  74. package/src/lib/ui/components/select/select.component.html +9 -4
  75. package/src/lib/ui/components/severity-badges/severity-badges.component.html +11 -0
  76. package/src/lib/ui/components/skeleton-detail/skeleton-detail.component.html +22 -0
  77. package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +12 -0
  78. package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.scss +0 -0
  79. package/src/lib/ui/components/slider/slider.component.html +3 -0
  80. package/src/lib/ui/components/slider/slider.component.scss +0 -0
  81. package/src/lib/ui/components/stat-cards/stat-cards.component.html +18 -0
  82. package/src/lib/ui/components/switch/switch.component.html +11 -6
  83. package/src/lib/ui/components/switch/switch.component.scss +0 -0
  84. package/src/lib/ui/components/tab-component/tab.component.scss +0 -0
  85. package/src/lib/ui/components/tab-group/tab-group.component.html +15 -1
  86. package/src/lib/ui/components/tab-group/tab-group.component.scss +51 -0
  87. package/src/lib/ui/components/table-cell/table-cell.component.scss +0 -0
  88. package/src/lib/ui/components/tag/tag.component.html +6 -1
  89. package/src/lib/ui/components/tag/tag.component.scss +0 -0
  90. package/src/lib/ui/components/toast/toast.component.html +2 -1
  91. package/src/lib/ui/components/toast/toast.component.scss +0 -0
  92. package/src/lib/ui/components/toast-container/toast-container.component.scss +0 -0
  93. package/src/lib/ui/components/tree-diagram/tree-diagram.component.scss +0 -0
  94. package/src/lib/ui/dialogs/confirmation/confirmation.component.html +1 -1
  95. package/src/lib/ui/dialogs/confirmation/confirmation.component.scss +0 -0
  96. package/tailwind.css +11 -8
  97. package/tokens.css +131 -0
  98. package/utilities.css +24 -0
  99. package/BeVietnamPro/BeVietnamPro-Bold.ttf +0 -0
  100. package/BeVietnamPro/BeVietnamPro-ExtraLight.ttf +0 -0
  101. package/BeVietnamPro/BeVietnamPro-Light.ttf +0 -0
  102. package/BeVietnamPro/BeVietnamPro-Medium.ttf +0 -0
  103. package/BeVietnamPro/BeVietnamPro-Regular.ttf +0 -0
  104. package/BeVietnamPro/BeVietnamPro-SemiBold.ttf +0 -0
  105. package/BeVietnamPro/BeVietnamPro-Thin.ttf +0 -0
  106. package/SpaceMono-Regular.ttf +0 -0
  107. package/dm-sans/DMSans-Bold.ttf +0 -0
  108. package/dm-sans/DMSans-Light.ttf +0 -0
  109. package/dm-sans/DMSans-Medium.ttf +0 -0
  110. package/dm-sans/DMSans-Regular.ttf +0 -0
  111. package/dm-sans/DMSans-SemiBold.ttf +0 -0
  112. package/dm-sans/DMSans-Thin.ttf +0 -0
  113. package/orbitron/Orbitron-Bold.ttf +0 -0
  114. package/orbitron/Orbitron-Medium.ttf +0 -0
  115. package/orbitron/Orbitron-Regular.ttf +0 -0
  116. package/orbitron/Orbitron-SemiBold.ttf +0 -0
  117. package/roboto/Roboto-Black.ttf +0 -0
  118. package/roboto/Roboto-BlackItalic.ttf +0 -0
  119. package/roboto/Roboto-Bold.ttf +0 -0
  120. package/roboto/Roboto-BoldCondensed.ttf +0 -0
  121. package/roboto/Roboto-BoldCondensedItalic.ttf +0 -0
  122. package/roboto/Roboto-BoldItalic.ttf +0 -0
  123. package/roboto/Roboto-Condensed.ttf +0 -0
  124. package/roboto/Roboto-CondensedItalic.ttf +0 -0
  125. package/roboto/Roboto-Italic.ttf +0 -0
  126. package/roboto/Roboto-Light.ttf +0 -0
  127. package/roboto/Roboto-LightItalic.ttf +0 -0
  128. package/roboto/Roboto-Medium.ttf +0 -0
  129. package/roboto/Roboto-MediumItalic.ttf +0 -0
  130. package/roboto/Roboto-Regular.ttf +0 -0
  131. package/roboto/Roboto-Thin.ttf +0 -0
  132. package/roboto/Roboto-ThinItalic.ttf +0 -0
  133. package/tailwind-config.d.ts +0 -4
  134. package/tailwind.config.js +0 -95
@@ -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))'
@@ -0,0 +1,49 @@
1
+ :host {
2
+ display: block;
3
+ width: 100%;
4
+ }
5
+
6
+ .chart-wrapper {
7
+ position: relative;
8
+ width: 100%;
9
+ height: 100%;
10
+ }
11
+
12
+ .chart-container {
13
+ width: 100%;
14
+ height: 100%;
15
+ }
16
+
17
+ .chart-loader {
18
+ position: absolute;
19
+ inset: 0;
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ background: rgba(var(--bg-primary-hover) / 0.6);
24
+ font-weight: 500;
25
+ font-size: 1.1rem;
26
+ z-index: 2;
27
+ border-radius: 4px;
28
+ }
29
+
30
+ .chart-empty {
31
+ display: flex;
32
+ flex-direction: column;
33
+ align-items: center;
34
+ justify-content: center;
35
+ height: 100%;
36
+ gap: 12px;
37
+ color: rgba(var(--text-secondary) / 1);
38
+ }
39
+
40
+ .chart-empty-icon {
41
+ width: 48px;
42
+ height: 48px;
43
+ opacity: 0.4;
44
+ }
45
+
46
+ .chart-empty-text {
47
+ font-size: 14px;
48
+ font-weight: 500;
49
+ }
@@ -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,
@@ -1,13 +1,14 @@
1
1
  <div class="flex flex-col mb-4 w-full text-left">
2
2
  @if (label) {
3
- <label class="txt-field-label">
3
+ <label class="txt-field-label" [attr.for]="fieldId">
4
4
  {{ label }}
5
- <span *ngIf="required" class="txt-required">*</span>
5
+ <span *ngIf="required" class="txt-required" aria-hidden="true">*</span>
6
6
  </label>
7
7
  }
8
8
 
9
9
  <div class="relative">
10
10
  <input
11
+ [id]="fieldId"
11
12
  [owlDateTimeTrigger]="picker"
12
13
  [owlDateTime]="picker"
13
14
  [placeholder]="placeholder"
@@ -0,0 +1,147 @@
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
+
4
+ // ─── Owl DateTime Picker Custom Styles ───────────────────────────────────────
5
+
6
+ // Container
7
+ ::ng-deep .owl-dt-container {
8
+ @apply bg-bg-primary rounded-xl shadow-xl border border-border-default;
9
+ width: 320px !important;
10
+ }
11
+
12
+ // Calendar table base
13
+ ::ng-deep .owl-dt-calendar-table {
14
+ @apply w-full border-collapse;
15
+ }
16
+
17
+ // Default cell hover — override red debug color
18
+ ::ng-deep .owl-dt-calendar-table :not(.owl-dt-calendar-cell-disabled):hover > .owl-dt-calendar-cell-content:not(.owl-dt-calendar-cell-selected) {
19
+ @apply bg-bg-hover;
20
+ }
21
+
22
+ // ── Current-month cell text color ─────────────────────────────────────────────
23
+ // No !important here — lets out-month and disabled !important overrides win.
24
+ // A direct declaration still beats the library's inherited rgba(0,0,0,.85).
25
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content {
26
+ color: rgb(var(--text-primary));
27
+ }
28
+
29
+ // Selected cell
30
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-selected {
31
+ background-color: rgb(var(--primary)) !important;
32
+ color: #fff !important;
33
+ }
34
+
35
+ // Today highlight (not selected)
36
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-today:not(.owl-dt-calendar-cell-selected) {
37
+ border-color: rgb(var(--primary)) !important;
38
+ }
39
+
40
+ // ── Disabled dates: text-text-placeholder ────────────────────────────────────
41
+ // owl-dt-calendar-cell-disabled is on the <td>, content span is a direct child
42
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-disabled > .owl-dt-calendar-cell-content {
43
+ color: rgb(var(--text-placeholder)) !important;
44
+ opacity: 0.6 !important;
45
+ cursor: not-allowed;
46
+ pointer-events: none;
47
+ }
48
+
49
+ // ── Other-month dates: text-text-secondary ────────────────────────────────────
50
+ // In v20, owl-dt-calendar-cell-out is applied ON the <span.owl-dt-calendar-cell-content>
51
+ // itself (via [ngClass]), NOT on the parent <td>. So target it directly.
52
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-cell-content.owl-dt-calendar-cell-out {
53
+ color: rgb(var(--text-secondary)) !important;
54
+ opacity: 0.6 !important;
55
+ }
56
+
57
+ // ── Timer input ───────────────────────────────────────────────────────────────
58
+ ::ng-deep .owl-dt-timer-content .owl-dt-timer-input {
59
+ @apply bg-bg-primary border border-border-strong text-text-primary rounded-lg;
60
+ }
61
+
62
+ // ── Period button (hide arrow) ────────────────────────────────────────────────
63
+ ::ng-deep .owl-dt-control-period-button .owl-dt-control-button-arrow {
64
+ display: none;
65
+ }
66
+
67
+ // ── Set / Cancel footer buttons ───────────────────────────────────────────────
68
+ // Library sets .owl-dt-container-buttons { height: 2em; color: #3f51b5 } — override both
69
+ ::ng-deep .owl-dt-container-buttons {
70
+ height: auto !important;
71
+ color: rgb(var(--text-primary)) !important; // reset inherited primary color on text
72
+ display: flex !important;
73
+ align-items: center !important;
74
+ justify-content: flex-end !important;
75
+ gap: 8px;
76
+ padding: 8px 12px;
77
+ border-top: 1px solid rgb(var(--border-default));
78
+ }
79
+
80
+ // Both buttons — explicit 32px height so inner height:100% resolves correctly
81
+ ::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button {
82
+ width: auto !important;
83
+ height: 32px !important;
84
+ border-radius: 6px !important;
85
+ width: 60px !important;
86
+ padding-top: 4px !important;
87
+ padding-bottom: 4px !important;
88
+ font-size: 13px !important;
89
+ font-weight: 600 !important;
90
+ border: 1px solid rgb(var(--border-default)) !important;
91
+ background-color: rgb(var(--bg-primary)) !important;
92
+ color: rgb(var(--text-primary)) !important;
93
+ cursor: pointer;
94
+ transition: opacity 150ms ease;
95
+
96
+ &:hover {
97
+ background-color: rgb(var(--bg-hover)) !important;
98
+ }
99
+ }
100
+
101
+ // "Set" = last button — primary fill
102
+ ::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button:last-child {
103
+ background-color: rgb(var(--primary)) !important;
104
+ border-color: rgb(var(--primary)) !important;
105
+ color: #fff !important;
106
+
107
+
108
+ &:hover {
109
+ opacity: 0.85;
110
+ }
111
+ }
112
+
113
+ // Inner content: height:100% now resolves against fixed 32px button, and
114
+ // background must be transparent so the button's own bg shows through
115
+ ::ng-deep .owl-dt-container-buttons .owl-dt-container-control-button .owl-dt-control-button-content {
116
+ height: 100% !important;
117
+ width: 100% !important;
118
+ padding: 0 !important;
119
+ background-color: transparent !important;
120
+ color: inherit !important;
121
+ display: flex !important;
122
+ align-items: center !important;
123
+ justify-content: center !important;
124
+ }
125
+
126
+ // ── Header / navigation ───────────────────────────────────────────────────────
127
+ ::ng-deep .owl-dt-calendar-control-content .owl-dt-control-button-content {
128
+ @apply text-text-primary font-medium;
129
+ }
130
+
131
+ ::ng-deep .owl-dt-control-arrow-button .owl-dt-control-button-content {
132
+ @apply text-text-primary;
133
+ }
134
+
135
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header {
136
+ @apply text-text-secondary;
137
+ }
138
+
139
+ ::ng-deep .owl-dt-calendar-table .owl-dt-calendar-header .owl-dt-weekdays th {
140
+ @apply text-text-secondary font-medium;
141
+ }
142
+
143
+ // ── Popup container border ────────────────────────────────────────────────────
144
+ ::ng-deep .owl-dt-inline-container,
145
+ ::ng-deep .owl-dt-popup-container {
146
+ @apply rounded-xl shadow-lg border border-border-strong;
147
+ }
@@ -0,0 +1,87 @@
1
+ :host {
2
+ --dnd-accent: rgba(var(--gradient-primary-start) / 1);
3
+ }
4
+
5
+ .dnd-wrapper {
6
+ display: block;
7
+ width: 100%;
8
+ }
9
+
10
+ .dnd-area {
11
+ display: flex;
12
+ flex-direction: column;
13
+ align-items: center;
14
+ justify-content: center;
15
+ gap: 12px;
16
+ min-height: 160px;
17
+ padding: 32px 24px;
18
+ border: 2px dashed color-mix(in srgb, var(--dnd-accent) 40%, transparent);
19
+ border-radius: 12px;
20
+ background: color-mix(in srgb, var(--dnd-accent) 4%, transparent);
21
+ cursor: pointer;
22
+ outline: none;
23
+ transition: all 0.2s ease;
24
+ position: relative;
25
+ }
26
+
27
+ .dnd-area:hover {
28
+ border-color: color-mix(in srgb, var(--dnd-accent) 70%, transparent);
29
+ background: color-mix(in srgb, var(--dnd-accent) 8%, transparent);
30
+ }
31
+
32
+ .dnd-area:focus-visible {
33
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--dnd-accent) 20%, transparent);
34
+ }
35
+
36
+ .dnd-area.drag-over {
37
+ border-color: var(--dnd-accent);
38
+ background: color-mix(in srgb, var(--dnd-accent) 10%, transparent);
39
+ }
40
+
41
+ .dnd-icon {
42
+ color: var(--dnd-accent);
43
+ }
44
+
45
+ .dnd-text {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 4px;
49
+ font-size: 14px;
50
+ flex-wrap: wrap;
51
+ justify-content: center;
52
+ }
53
+
54
+ .dnd-link {
55
+ color: var(--dnd-accent);
56
+ font-weight: 600;
57
+ text-decoration: underline;
58
+ }
59
+
60
+ .dnd-or {
61
+ color: rgba(var(--text-secondary) / 1);
62
+ }
63
+
64
+ .dnd-hint {
65
+ font-size: 12px;
66
+ color: rgba(var(--text-secondary) / 0.7);
67
+ }
68
+
69
+ .dnd-input {
70
+ position: absolute;
71
+ width: 0;
72
+ height: 0;
73
+ overflow: hidden;
74
+ opacity: 0;
75
+ }
76
+
77
+ /* Responsive */
78
+ @media (max-width: 640px) {
79
+ .dnd-area {
80
+ min-height: 120px;
81
+ padding: 24px 16px;
82
+ }
83
+
84
+ .dnd-text {
85
+ font-size: 13px;
86
+ }
87
+ }
@@ -7,6 +7,7 @@
7
7
  @if (logo) {
8
8
  <img
9
9
  [src]="logo"
10
+ alt="Home"
10
11
  class="h-[20px] w-auto transition-all duration-300 ease-in-out"
11
12
  [ngClass]="{ 'scale-90': !isExpanded, 'ml-5': isExpanded }"
12
13
  />
@@ -35,6 +36,8 @@
35
36
  <button
36
37
  type="button"
37
38
  class="toggle-btn"
39
+ [attr.aria-label]="isExpanded ? 'Collapse navigation' : 'Expand navigation'"
40
+ [attr.aria-expanded]="isExpanded"
38
41
  (click)="toggleDrawer()"
39
42
  [matTooltip]="isExpanded ? 'Collapse' : 'Expand'"
40
43
  matTooltipClass="text-text-primary text-xs font-semibold"
@@ -0,0 +1,134 @@
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
+
4
+ :host {
5
+ @apply block h-full;
6
+ }
7
+
8
+ .drawer-host-wrapper {
9
+ @apply relative h-full border-r border-border-default;
10
+ }
11
+
12
+ .drawer-container {
13
+ @apply px-2 h-full bg-bg-primary flex flex-col overflow-auto;
14
+ transition: width 300ms cubic-bezier(0.4, 0, 0.2, 1);
15
+ }
16
+
17
+ /* Floating toggle button — sits on the right border, vertically centered */
18
+ .toggle-btn {
19
+ @apply absolute top-1/2 -translate-y-1/2 z-50 flex items-center justify-center w-6 h-6 rounded-full bg-bg-primary border border-border-default cursor-pointer shadow-sm;
20
+ right: -12px; /* half of button width to straddle the border */
21
+ transition: all 200ms ease;
22
+
23
+ &:hover {
24
+ @apply bg-bg-hover shadow-md;
25
+ }
26
+
27
+ &:active {
28
+ transform: translateY(-50%) scale(0.9);
29
+ }
30
+
31
+ &:focus-visible {
32
+ @apply outline-2 outline-primary outline-offset-2;
33
+ }
34
+ }
35
+
36
+ .drawer-nav {
37
+ @apply flex-1 overflow-y-auto overflow-x-hidden py-2;
38
+
39
+ /* Custom scrollbar */
40
+ &::-webkit-scrollbar {
41
+ @apply w-1.5;
42
+ }
43
+
44
+ &::-webkit-scrollbar-track {
45
+ @apply bg-transparent;
46
+ }
47
+
48
+ &::-webkit-scrollbar-thumb {
49
+ @apply bg-border-default rounded-sm;
50
+
51
+ &:hover {
52
+ @apply bg-text-placeholder;
53
+ }
54
+ }
55
+ }
56
+
57
+ .drawer-item-wrapper {
58
+ @apply relative;
59
+ }
60
+
61
+ .drawer-item {
62
+ @apply flex items-center mt-1 w-full min-h-8 py-2 px-large border-none bg-transparent cursor-pointer no-underline text-text-primary relative rounded;
63
+ transition: all 200ms ease;
64
+
65
+ &:hover {
66
+ @apply bg-bg-hover text-text-primary scale-95;
67
+ }
68
+
69
+ &.active {
70
+ @apply bg-gradient-primary text-white font-medium;
71
+
72
+ .item-icon {
73
+ @apply text-white;
74
+ }
75
+ }
76
+
77
+ &:active {
78
+ transform: scale(0.98);
79
+ }
80
+
81
+ &:focus-visible {
82
+ @apply outline-2 outline-primary outline-offset-2;
83
+ }
84
+
85
+ -webkit-tap-highlight-color: transparent;
86
+ @apply outline-none;
87
+ }
88
+
89
+ .item-content {
90
+ @apply flex items-center gap-3 w-full overflow-hidden;
91
+ }
92
+
93
+ .item-icon {
94
+ @apply flex-shrink-0;
95
+ color: inherit;
96
+ }
97
+
98
+ .item-label {
99
+ @apply flex-1 whitespace-nowrap overflow-hidden text-ellipsis text-[13px] leading-5 text-left;
100
+ }
101
+
102
+ .chevron-icon {
103
+ @apply flex-shrink-0 ml-auto text-text-primary;
104
+ transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);
105
+
106
+ &.rotated {
107
+ transform: rotate(180deg);
108
+ }
109
+ }
110
+
111
+ .accordion-children {
112
+ @apply overflow-hidden;
113
+ }
114
+
115
+ .drawer-version {
116
+ @apply flex items-center justify-center py-3 px-4 text-text-placeholder text-[11px] border-t border-border-default select-none;
117
+ font-family: 'Roboto', monospace;
118
+ }
119
+
120
+ .drawer-version-dot {
121
+ @apply block w-1.5 h-1.5 rounded-full bg-text-placeholder;
122
+ }
123
+
124
+ /* Collapsed mode: center the icons */
125
+ .drawer-container[style*='width: 64px'] {
126
+ .drawer-item {
127
+ @apply justify-center;
128
+ padding-left: 16px !important;
129
+ }
130
+
131
+ .item-content {
132
+ @apply justify-center;
133
+ }
134
+ }
@@ -0,0 +1,9 @@
1
+ <div
2
+ class="flex flex-col items-center justify-center gap-small w-full"
3
+ [style.minHeight]="height"
4
+ >
5
+ @if (icon) {
6
+ <fx-ui-hero-icon class="text-text-placeholder" [icon]="icon" [size]="24"></fx-ui-hero-icon>
7
+ }
8
+ <div class="txt-default text-text-placeholder">{{ message }}</div>
9
+ </div>
@@ -0,0 +1,12 @@
1
+ <div class="flex flex-wrap items-center gap-small">
2
+ @for (option of options; track option.value) {
3
+ <button
4
+ type="button"
5
+ class="px-3 py-1 rounded-full txt-utility-caption font-medium transition-colors cursor-pointer"
6
+ [ngClass]="chipClass(option)"
7
+ (click)="select(option)"
8
+ >
9
+ {{ option.label }}
10
+ </button>
11
+ }
12
+ </div>
@@ -0,0 +1,4 @@
1
+ <div class="flex flex-col gap-small min-w-0">
2
+ <span class="txt-field-label !mb-0">{{ label }}</span>
3
+ <span class="txt-default" [ngClass]="valueClass">{{ displayValue }}</span>
4
+ </div>
@@ -1,9 +1,9 @@
1
1
  <div class="mb-4 text-left w-full text-text-primary" [class]="class">
2
2
  @if (label) {
3
- <label class="block txt-field-label">
3
+ <label class="block txt-field-label" [attr.for]="fieldId">
4
4
  {{ label }}
5
5
  @if (required) {
6
- <span class="txt-required">*</span>
6
+ <span class="txt-required" aria-hidden="true">*</span>
7
7
  }
8
8
  @if (tooltip) {
9
9
  <fx-ui-hero-icon
@@ -22,6 +22,7 @@
22
22
  <input
23
23
  appTrimOnBlur
24
24
  [appTrimOnBlurCollapse]="true"
25
+ [id]="fieldId"
25
26
  [type]="displayType"
26
27
  [placeholder]="placeholder"
27
28
  [disabled]="disabled"
@@ -30,6 +31,9 @@
30
31
  (blur)="onBlur()"
31
32
  (focus)="onFocus()"
32
33
  [attr.maxlength]="maxlength"
34
+ [attr.aria-invalid]="invalid || null"
35
+ [attr.aria-describedby]="invalid ? fieldId + '-error' : null"
36
+ [attr.aria-required]="required ? true : null"
33
37
  [class]="type === 'otp' ? 'input-otp' : 'input-default'"
34
38
  [class.input-invalid]="invalid"
35
39
  [class.pr-8]="type === 'password' || suffixIcon"
@@ -41,18 +45,26 @@
41
45
  class="absolute inset-y-0 right-2 flex items-center text-text-primary hover:text-text-secondary"
42
46
  (click)="onSuffixClick()"
43
47
  [disabled]="disabled"
48
+ [attr.aria-label]="
49
+ type === 'password'
50
+ ? (showPassword ? 'Hide password' : 'Show password')
51
+ : (suffixAriaLabel || null)
52
+ "
53
+ [attr.aria-pressed]="type === 'password' ? showPassword : null"
44
54
  >
45
55
  @if (type === 'password') {
46
56
  <fx-ui-hero-icon
47
57
  [icon]="showPassword ? 'eye-slash' : 'eye'"
48
58
  [size]="18"
49
59
  class="text-text-primary"
60
+ aria-hidden="true"
50
61
  ></fx-ui-hero-icon>
51
62
  } @else if (suffixIcon) {
52
63
  <fx-ui-hero-icon
53
64
  [icon]="suffixIcon"
54
65
  [size]="18"
55
66
  class="text-text-primary"
67
+ aria-hidden="true"
56
68
  ></fx-ui-hero-icon>
57
69
  }
58
70
  </button>
@@ -60,7 +72,7 @@
60
72
  </div>
61
73
 
62
74
  @if (invalid) {
63
- <div class="txt-invalid">
75
+ <div class="txt-invalid" role="alert" [id]="fieldId + '-error'">
64
76
  {{ getErrorMessage(label) }}
65
77
  </div>
66
78
  }
@@ -0,0 +1,70 @@
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
+
4
+ .kanban-board {
5
+ @apply w-full h-full overflow-x-auto;
6
+ }
7
+
8
+ .kanban-columns {
9
+ @apply flex gap-4 p-4 min-h-full;
10
+ }
11
+
12
+ .kanban-column {
13
+ @apply flex flex-col min-w-[300px] bg-gray-50 dark:bg-gray-800 rounded-lg;
14
+ flex-shrink: 0;
15
+ }
16
+
17
+ .kanban-column-header {
18
+ @apply flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700;
19
+ }
20
+
21
+ .kanban-column-title {
22
+ @apply text-lg font-semibold text-gray-900 dark:text-gray-100 m-0;
23
+ }
24
+
25
+ .kanban-column-count {
26
+ @apply px-2 py-1 text-sm font-medium bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-full;
27
+ }
28
+
29
+ .kanban-column-content {
30
+ @apply flex-1 p-4 space-y-3 overflow-y-auto;
31
+ min-height: 200px;
32
+ }
33
+
34
+ .kanban-item {
35
+ @apply bg-white dark:bg-gray-700 rounded-lg shadow-sm border border-gray-200 dark:border-gray-600;
36
+ @apply transition-shadow duration-200;
37
+ cursor: move;
38
+
39
+ &:hover {
40
+ @apply shadow-md;
41
+ }
42
+ }
43
+
44
+ .kanban-item-default {
45
+ @apply p-4 text-gray-900 dark:text-gray-100;
46
+ }
47
+
48
+ .kanban-item-placeholder {
49
+ @apply bg-gray-200 dark:bg-gray-600 rounded-lg border-2 border-dashed border-gray-400 dark:border-gray-500;
50
+ @apply opacity-50;
51
+ min-height: 60px;
52
+ }
53
+
54
+ .kanban-column-empty {
55
+ @apply flex items-center justify-center h-32 text-gray-400 dark:text-gray-500 text-sm;
56
+ @apply border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg;
57
+ }
58
+
59
+ // CDK Drag and Drop Styles
60
+ .cdk-drag-preview {
61
+ @apply opacity-80 shadow-lg rounded-lg;
62
+ }
63
+
64
+ .cdk-drag-animating {
65
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
66
+ }
67
+
68
+ .kanban-column-content.cdk-drop-list-dragging .kanban-item:not(.cdk-drag-placeholder) {
69
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
70
+ }
@@ -0,0 +1,11 @@
1
+ /* Full-width when stacked; fixed width beside the detail pane on lg+ (1080px). */
2
+ .fx-md-list {
3
+ width: 100%;
4
+ }
5
+
6
+ @media (min-width: 1080px) {
7
+ .fx-md-list {
8
+ width: var(--fx-md-list-width, 420px);
9
+ flex-shrink: 0;
10
+ }
11
+ }