@aurelia-ui-toolkits/headless 1.0.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 (284) hide show
  1. package/dist/alert/ui-alert.html +19 -0
  2. package/dist/alert/ui-alert.js +67 -0
  3. package/dist/alert/ui-alert.js.map +1 -0
  4. package/dist/alert-service/alert-configuration.js +11 -0
  5. package/dist/alert-service/alert-configuration.js.map +1 -0
  6. package/dist/alert-service/alert-modal/alert-modal.html +12 -0
  7. package/dist/alert-service/alert-modal/alert-modal.js +31 -0
  8. package/dist/alert-service/alert-modal/alert-modal.js.map +1 -0
  9. package/dist/alert-service/alert-modal/i-alert-modal-payload.js +2 -0
  10. package/dist/alert-service/alert-modal/i-alert-modal-payload.js.map +1 -0
  11. package/dist/alert-service/alert-service.js +108 -0
  12. package/dist/alert-service/alert-service.js.map +1 -0
  13. package/dist/alert-service/decorators/confirm-action.js +14 -0
  14. package/dist/alert-service/decorators/confirm-action.js.map +1 -0
  15. package/dist/alert-service/decorators/using-progress.js +23 -0
  16. package/dist/alert-service/decorators/using-progress.js.map +1 -0
  17. package/dist/alert-service/exceptions-tracker.js +4 -0
  18. package/dist/alert-service/exceptions-tracker.js.map +1 -0
  19. package/dist/alert-service/prompt-dialog/prompt-dialog.html +13 -0
  20. package/dist/alert-service/prompt-dialog/prompt-dialog.js +39 -0
  21. package/dist/alert-service/prompt-dialog/prompt-dialog.js.map +1 -0
  22. package/dist/badge/ui-badge.html +6 -0
  23. package/dist/badge/ui-badge.js +44 -0
  24. package/dist/badge/ui-badge.js.map +1 -0
  25. package/dist/base/boolean-attr.js +4 -0
  26. package/dist/base/boolean-attr.js.map +1 -0
  27. package/dist/base/i-validated-element.js +2 -0
  28. package/dist/base/i-validated-element.js.map +1 -0
  29. package/dist/base/keys.js +14 -0
  30. package/dist/base/keys.js.map +1 -0
  31. package/dist/breadcrumbs/ui-breadcrumbs.html +10 -0
  32. package/dist/breadcrumbs/ui-breadcrumbs.js +31 -0
  33. package/dist/breadcrumbs/ui-breadcrumbs.js.map +1 -0
  34. package/dist/button/enhance-ui-button.js +25 -0
  35. package/dist/button/enhance-ui-button.js.map +1 -0
  36. package/dist/button/ui-button.html +20 -0
  37. package/dist/button/ui-button.js +77 -0
  38. package/dist/button/ui-button.js.map +1 -0
  39. package/dist/button/ui-icon-button.html +20 -0
  40. package/dist/button/ui-icon-button.js +77 -0
  41. package/dist/button/ui-icon-button.js.map +1 -0
  42. package/dist/checkbox/ui-checkbox.html +32 -0
  43. package/dist/checkbox/ui-checkbox.js +186 -0
  44. package/dist/checkbox/ui-checkbox.js.map +1 -0
  45. package/dist/chip/ui-chip.html +32 -0
  46. package/dist/chip/ui-chip.js +129 -0
  47. package/dist/chip/ui-chip.js.map +1 -0
  48. package/dist/combobox/enhance-ui-combobox.js +26 -0
  49. package/dist/combobox/enhance-ui-combobox.js.map +1 -0
  50. package/dist/combobox/ui-combobox.html +76 -0
  51. package/dist/combobox/ui-combobox.js +478 -0
  52. package/dist/combobox/ui-combobox.js.map +1 -0
  53. package/dist/disclosure/ui-disclosure.html +28 -0
  54. package/dist/disclosure/ui-disclosure.js +75 -0
  55. package/dist/disclosure/ui-disclosure.js.map +1 -0
  56. package/dist/drawer/ui-drawer.html +35 -0
  57. package/dist/drawer/ui-drawer.js +246 -0
  58. package/dist/drawer/ui-drawer.js.map +1 -0
  59. package/dist/index.js +135 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/input/enhance-ui-input.js +26 -0
  62. package/dist/input/enhance-ui-input.js.map +1 -0
  63. package/dist/input/ui-input.html +56 -0
  64. package/dist/input/ui-input.js +259 -0
  65. package/dist/input/ui-input.js.map +1 -0
  66. package/dist/list/ui-list-item.html +22 -0
  67. package/dist/list/ui-list-item.js +59 -0
  68. package/dist/list/ui-list-item.js.map +1 -0
  69. package/dist/list/ui-list.html +10 -0
  70. package/dist/list/ui-list.js +316 -0
  71. package/dist/list/ui-list.js.map +1 -0
  72. package/dist/menu/ui-menu.html +20 -0
  73. package/dist/menu/ui-menu.js +154 -0
  74. package/dist/menu/ui-menu.js.map +1 -0
  75. package/dist/popup/ui-popup.html +16 -0
  76. package/dist/popup/ui-popup.js +397 -0
  77. package/dist/popup/ui-popup.js.map +1 -0
  78. package/dist/progress/ui-progress.html +17 -0
  79. package/dist/progress/ui-progress.js +76 -0
  80. package/dist/progress/ui-progress.js.map +1 -0
  81. package/dist/radio/ui-radio-group.html +27 -0
  82. package/dist/radio/ui-radio-group.js +259 -0
  83. package/dist/radio/ui-radio-group.js.map +1 -0
  84. package/dist/radio/ui-radio.html +11 -0
  85. package/dist/radio/ui-radio.js +55 -0
  86. package/dist/radio/ui-radio.js.map +1 -0
  87. package/dist/segmented-control/ui-segment.html +10 -0
  88. package/dist/segmented-control/ui-segment.js +44 -0
  89. package/dist/segmented-control/ui-segment.js.map +1 -0
  90. package/dist/segmented-control/ui-segmented-control.html +9 -0
  91. package/dist/segmented-control/ui-segmented-control.js +134 -0
  92. package/dist/segmented-control/ui-segmented-control.js.map +1 -0
  93. package/dist/select/enhance-ui-select.js +26 -0
  94. package/dist/select/enhance-ui-select.js.map +1 -0
  95. package/dist/select/ui-select.html +70 -0
  96. package/dist/select/ui-select.js +323 -0
  97. package/dist/select/ui-select.js.map +1 -0
  98. package/dist/slider/ui-slider.html +69 -0
  99. package/dist/slider/ui-slider.js +362 -0
  100. package/dist/slider/ui-slider.js.map +1 -0
  101. package/dist/splitter/ui-splitter.html +14 -0
  102. package/dist/splitter/ui-splitter.js +257 -0
  103. package/dist/splitter/ui-splitter.js.map +1 -0
  104. package/dist/switch/ui-switch.html +23 -0
  105. package/dist/switch/ui-switch.js +121 -0
  106. package/dist/switch/ui-switch.js.map +1 -0
  107. package/dist/table/enhance-ui-table.js +25 -0
  108. package/dist/table/enhance-ui-table.js.map +1 -0
  109. package/dist/table/ui-table-column.html +17 -0
  110. package/dist/table/ui-table-column.js +127 -0
  111. package/dist/table/ui-table-column.js.map +1 -0
  112. package/dist/table/ui-table.html +56 -0
  113. package/dist/table/ui-table.js +225 -0
  114. package/dist/table/ui-table.js.map +1 -0
  115. package/dist/tabs/ui-tab.html +10 -0
  116. package/dist/tabs/ui-tab.js +52 -0
  117. package/dist/tabs/ui-tab.js.map +1 -0
  118. package/dist/tabs/ui-tabs.html +3 -0
  119. package/dist/tabs/ui-tabs.js +112 -0
  120. package/dist/tabs/ui-tabs.js.map +1 -0
  121. package/dist/toast/ui-toast-region.html +11 -0
  122. package/dist/toast/ui-toast-region.js +38 -0
  123. package/dist/toast/ui-toast-region.js.map +1 -0
  124. package/dist/toast/ui-toast-service.js +70 -0
  125. package/dist/toast/ui-toast-service.js.map +1 -0
  126. package/dist/tooltip/ui-tooltip-service.js +63 -0
  127. package/dist/tooltip/ui-tooltip-service.js.map +1 -0
  128. package/dist/tooltip/ui-tooltip.js +221 -0
  129. package/dist/tooltip/ui-tooltip.js.map +1 -0
  130. package/dist/top-app-bar/ui-top-app-bar.html +24 -0
  131. package/dist/top-app-bar/ui-top-app-bar.js +68 -0
  132. package/dist/top-app-bar/ui-top-app-bar.js.map +1 -0
  133. package/dist/tree/ui-tree.html +38 -0
  134. package/dist/tree/ui-tree.js +340 -0
  135. package/dist/tree/ui-tree.js.map +1 -0
  136. package/dist/types/alert/ui-alert.d.ts +11 -0
  137. package/dist/types/alert-service/alert-configuration.d.ts +8 -0
  138. package/dist/types/alert-service/alert-modal/alert-modal.d.ts +7 -0
  139. package/dist/types/alert-service/alert-modal/i-alert-modal-payload.d.ts +14 -0
  140. package/dist/types/alert-service/alert-service.d.ts +17 -0
  141. package/dist/types/alert-service/decorators/confirm-action.d.ts +3 -0
  142. package/dist/types/alert-service/decorators/using-progress.d.ts +6 -0
  143. package/dist/types/alert-service/exceptions-tracker.d.ts +3 -0
  144. package/dist/types/alert-service/prompt-dialog/prompt-dialog.d.ts +17 -0
  145. package/dist/types/badge/ui-badge.d.ts +7 -0
  146. package/dist/types/base/boolean-attr.d.ts +1 -0
  147. package/dist/types/base/i-validated-element.d.ts +10 -0
  148. package/dist/types/base/keys.d.ts +12 -0
  149. package/dist/types/breadcrumbs/ui-breadcrumbs.d.ts +8 -0
  150. package/dist/types/button/enhance-ui-button.d.ts +3 -0
  151. package/dist/types/button/ui-button.d.ts +16 -0
  152. package/dist/types/button/ui-icon-button.d.ts +18 -0
  153. package/dist/types/checkbox/ui-checkbox.d.ts +32 -0
  154. package/dist/types/chip/ui-chip.d.ts +26 -0
  155. package/dist/types/combobox/enhance-ui-combobox.d.ts +3 -0
  156. package/dist/types/combobox/ui-combobox.d.ts +79 -0
  157. package/dist/types/disclosure/ui-disclosure.d.ts +18 -0
  158. package/dist/types/drawer/ui-drawer.d.ts +38 -0
  159. package/dist/types/index.d.ts +91 -0
  160. package/dist/types/input/enhance-ui-input.d.ts +3 -0
  161. package/dist/types/input/ui-input.d.ts +44 -0
  162. package/dist/types/list/ui-list-item.d.ts +10 -0
  163. package/dist/types/list/ui-list.d.ts +45 -0
  164. package/dist/types/menu/ui-menu.d.ts +29 -0
  165. package/dist/types/popup/ui-popup.d.ts +61 -0
  166. package/dist/types/progress/ui-progress.d.ts +15 -0
  167. package/dist/types/radio/ui-radio-group.d.ts +37 -0
  168. package/dist/types/radio/ui-radio.d.ts +11 -0
  169. package/dist/types/segmented-control/ui-segment.d.ts +8 -0
  170. package/dist/types/segmented-control/ui-segmented-control.d.ts +17 -0
  171. package/dist/types/select/enhance-ui-select.d.ts +3 -0
  172. package/dist/types/select/ui-select.d.ts +50 -0
  173. package/dist/types/slider/ui-slider.d.ts +58 -0
  174. package/dist/types/splitter/ui-splitter.d.ts +39 -0
  175. package/dist/types/switch/ui-switch.d.ts +23 -0
  176. package/dist/types/table/enhance-ui-table.d.ts +3 -0
  177. package/dist/types/table/ui-table-column.d.ts +22 -0
  178. package/dist/types/table/ui-table.d.ts +51 -0
  179. package/dist/types/tabs/ui-tab.d.ts +10 -0
  180. package/dist/types/tabs/ui-tabs.d.ts +16 -0
  181. package/dist/types/toast/ui-toast-region.d.ts +6 -0
  182. package/dist/types/toast/ui-toast-service.d.ts +28 -0
  183. package/dist/types/tooltip/ui-tooltip-service.d.ts +23 -0
  184. package/dist/types/tooltip/ui-tooltip.d.ts +35 -0
  185. package/dist/types/top-app-bar/ui-top-app-bar.d.ts +9 -0
  186. package/dist/types/tree/ui-tree.d.ts +70 -0
  187. package/dist/types/validation/ui-validation-controller-factory.d.ts +7 -0
  188. package/dist/types/validation/ui-validation-result-presenter.d.ts +4 -0
  189. package/dist/types/validation/validate.d.ts +13 -0
  190. package/dist/validation/ui-validation-controller-factory.js +17 -0
  191. package/dist/validation/ui-validation-controller-factory.js.map +1 -0
  192. package/dist/validation/ui-validation-result-presenter.js +23 -0
  193. package/dist/validation/ui-validation-result-presenter.js.map +1 -0
  194. package/dist/validation/validate.js +24 -0
  195. package/dist/validation/validate.js.map +1 -0
  196. package/package.json +50 -0
  197. package/src/alert/ui-alert.html +19 -0
  198. package/src/alert/ui-alert.ts +33 -0
  199. package/src/alert-service/alert-configuration.ts +11 -0
  200. package/src/alert-service/alert-modal/alert-modal.html +12 -0
  201. package/src/alert-service/alert-modal/alert-modal.ts +19 -0
  202. package/src/alert-service/alert-modal/i-alert-modal-payload.ts +14 -0
  203. package/src/alert-service/alert-service.ts +116 -0
  204. package/src/alert-service/decorators/confirm-action.ts +18 -0
  205. package/src/alert-service/decorators/using-progress.ts +32 -0
  206. package/src/alert-service/exceptions-tracker.ts +3 -0
  207. package/src/alert-service/prompt-dialog/prompt-dialog.html +13 -0
  208. package/src/alert-service/prompt-dialog/prompt-dialog.ts +37 -0
  209. package/src/badge/ui-badge.html +6 -0
  210. package/src/badge/ui-badge.ts +17 -0
  211. package/src/base/boolean-attr.ts +3 -0
  212. package/src/base/i-validated-element.ts +11 -0
  213. package/src/base/keys.ts +12 -0
  214. package/src/breadcrumbs/ui-breadcrumbs.html +10 -0
  215. package/src/breadcrumbs/ui-breadcrumbs.ts +14 -0
  216. package/src/button/enhance-ui-button.ts +9 -0
  217. package/src/button/ui-button.html +20 -0
  218. package/src/button/ui-button.ts +60 -0
  219. package/src/button/ui-icon-button.html +20 -0
  220. package/src/button/ui-icon-button.ts +62 -0
  221. package/src/checkbox/ui-checkbox.html +32 -0
  222. package/src/checkbox/ui-checkbox.ts +188 -0
  223. package/src/chip/ui-chip.html +32 -0
  224. package/src/chip/ui-chip.ts +118 -0
  225. package/src/combobox/enhance-ui-combobox.ts +10 -0
  226. package/src/combobox/ui-combobox.html +76 -0
  227. package/src/combobox/ui-combobox.ts +450 -0
  228. package/src/disclosure/ui-disclosure.html +28 -0
  229. package/src/disclosure/ui-disclosure.ts +68 -0
  230. package/src/drawer/ui-drawer.html +35 -0
  231. package/src/drawer/ui-drawer.ts +219 -0
  232. package/src/index.ts +152 -0
  233. package/src/input/enhance-ui-input.ts +10 -0
  234. package/src/input/ui-input.html +56 -0
  235. package/src/input/ui-input.ts +225 -0
  236. package/src/list/ui-list-item.html +22 -0
  237. package/src/list/ui-list-item.ts +25 -0
  238. package/src/list/ui-list.html +10 -0
  239. package/src/list/ui-list.ts +330 -0
  240. package/src/menu/ui-menu.html +20 -0
  241. package/src/menu/ui-menu.ts +103 -0
  242. package/src/popup/ui-popup.html +16 -0
  243. package/src/popup/ui-popup.ts +391 -0
  244. package/src/progress/ui-progress.html +17 -0
  245. package/src/progress/ui-progress.ts +51 -0
  246. package/src/radio/ui-radio-group.html +27 -0
  247. package/src/radio/ui-radio-group.ts +250 -0
  248. package/src/radio/ui-radio.html +11 -0
  249. package/src/radio/ui-radio.ts +35 -0
  250. package/src/resource.d.ts +4 -0
  251. package/src/segmented-control/ui-segment.html +10 -0
  252. package/src/segmented-control/ui-segment.ts +20 -0
  253. package/src/segmented-control/ui-segmented-control.html +9 -0
  254. package/src/segmented-control/ui-segmented-control.ts +119 -0
  255. package/src/select/enhance-ui-select.ts +10 -0
  256. package/src/select/ui-select.html +70 -0
  257. package/src/select/ui-select.ts +294 -0
  258. package/src/slider/ui-slider.html +69 -0
  259. package/src/slider/ui-slider.ts +329 -0
  260. package/src/splitter/ui-splitter.html +14 -0
  261. package/src/splitter/ui-splitter.ts +249 -0
  262. package/src/switch/ui-switch.html +23 -0
  263. package/src/switch/ui-switch.ts +121 -0
  264. package/src/table/enhance-ui-table.ts +9 -0
  265. package/src/table/ui-table-column.html +17 -0
  266. package/src/table/ui-table-column.ts +108 -0
  267. package/src/table/ui-table.html +56 -0
  268. package/src/table/ui-table.ts +209 -0
  269. package/src/tabs/ui-tab.html +10 -0
  270. package/src/tabs/ui-tab.ts +30 -0
  271. package/src/tabs/ui-tabs.html +3 -0
  272. package/src/tabs/ui-tabs.ts +105 -0
  273. package/src/toast/ui-toast-region.html +11 -0
  274. package/src/toast/ui-toast-region.ts +18 -0
  275. package/src/toast/ui-toast-service.ts +100 -0
  276. package/src/tooltip/ui-tooltip-service.ts +84 -0
  277. package/src/tooltip/ui-tooltip.ts +200 -0
  278. package/src/top-app-bar/ui-top-app-bar.html +24 -0
  279. package/src/top-app-bar/ui-top-app-bar.ts +27 -0
  280. package/src/tree/ui-tree.html +38 -0
  281. package/src/tree/ui-tree.ts +363 -0
  282. package/src/validation/ui-validation-controller-factory.ts +20 -0
  283. package/src/validation/ui-validation-result-presenter.ts +26 -0
  284. package/src/validation/validate.ts +35 -0
@@ -0,0 +1,250 @@
1
+ import { bindable, BindingMode, CustomElement, customElement, INode, resolve, slotted } from 'aurelia';
2
+ import { booleanAttr } from '../base/boolean-attr';
3
+ import { IError, IValidatedElement } from '../base/i-validated-element';
4
+ import { Keys } from '../base/keys';
5
+ import { UiRadio } from './ui-radio';
6
+ import template from './ui-radio-group.html?raw';
7
+
8
+ let nextRadioGroupId = 0;
9
+
10
+ @customElement({ name: 'ui-radio-group', template })
11
+ export class UiRadioGroup {
12
+ constructor() {
13
+ defineUiRadioGroupElementApis(this.element);
14
+ }
15
+
16
+ readonly element = resolve(INode) as HTMLElement;
17
+
18
+ errors = new Map<IError, boolean>();
19
+ focus: boolean = false;
20
+
21
+ @bindable({ mode: BindingMode.twoWay })
22
+ value: unknown;
23
+
24
+ @bindable
25
+ label: string | undefined;
26
+
27
+ @bindable
28
+ helperText: string | undefined;
29
+
30
+ @bindable
31
+ id: string = `ui-radio-group-${++nextRadioGroupId}`;
32
+
33
+ @bindable({ set: booleanAttr })
34
+ disabled: boolean = false;
35
+
36
+ @bindable({ set: booleanAttr })
37
+ readonly: boolean = false;
38
+
39
+ @bindable({ set: booleanAttr })
40
+ required: boolean = false;
41
+
42
+ @bindable({ set: booleanAttr })
43
+ invalid: boolean = false;
44
+
45
+ @slotted({ slotName: 'helper' })
46
+ helperNodes: readonly Node[] = [];
47
+
48
+ @slotted('ui-radio')
49
+ radioElements: readonly HTMLElement[] = [];
50
+
51
+ get radios(): UiRadio[] {
52
+ return this.radioElements.map(element => CustomElement.for<UiRadio>(element).viewModel);
53
+ }
54
+
55
+ get labelId(): string {
56
+ return `${this.id}-label`;
57
+ }
58
+
59
+ get helperId(): string {
60
+ return `${this.id}-helper`;
61
+ }
62
+
63
+ get errorsId(): string {
64
+ return `${this.id}-errors`;
65
+ }
66
+
67
+ select(value: unknown): void {
68
+ if (this.disabled || this.readonly || this.value === value) {
69
+ return;
70
+ }
71
+
72
+ this.value = value;
73
+ this.dispatchValueEvent('input');
74
+ this.dispatchValueEvent('change');
75
+ }
76
+
77
+ isSelected(radio: UiRadio): boolean {
78
+ return this.value === radio.value;
79
+ }
80
+
81
+ addError(error: IError): void {
82
+ if (this.findError(error)) {
83
+ return;
84
+ }
85
+
86
+ this.errors.set(error, true);
87
+ }
88
+
89
+ removeError(error: IError): void {
90
+ const existing = this.findError(error);
91
+ if (existing) {
92
+ this.errors.delete(existing);
93
+ return;
94
+ }
95
+
96
+ this.errors.delete(error);
97
+ }
98
+
99
+ onRadioKeyDown(radio: UiRadio, event: KeyboardEvent): void {
100
+ if (this.disabled || this.readonly) {
101
+ return;
102
+ }
103
+
104
+ const radios = this.enabledRadios;
105
+ if (!radios.length) {
106
+ return;
107
+ }
108
+
109
+ if (event.key === Keys.Space || event.key === Keys.Enter) {
110
+ if (!radio.disabled) {
111
+ event.preventDefault();
112
+ this.select(radio.value);
113
+ }
114
+ return;
115
+ }
116
+
117
+ if (event.key === Keys.Home) {
118
+ event.preventDefault();
119
+ this.focusRadio(radios[0]);
120
+ return;
121
+ }
122
+
123
+ if (event.key === Keys.End) {
124
+ event.preventDefault();
125
+ this.focusRadio(radios[radios.length - 1]);
126
+ return;
127
+ }
128
+
129
+ const direction = this.getNavigationDirection(event.key);
130
+ if (!direction) {
131
+ return;
132
+ }
133
+
134
+ event.preventDefault();
135
+ const index = radios.indexOf(radio);
136
+ this.focusRadio(radios[(index + direction + radios.length) % radios.length]);
137
+ }
138
+
139
+ onFocusIn(): void {
140
+ if (!this.disabled) {
141
+ this.focus = true;
142
+ }
143
+ }
144
+
145
+ onFocusOut(): void {
146
+ this.focus = false;
147
+ }
148
+
149
+ get enabledRadios(): UiRadio[] {
150
+ return this.radios.filter(radio => !radio.disabled);
151
+ }
152
+
153
+ private focusRadio(radio: UiRadio): void {
154
+ radio.element.focus();
155
+ }
156
+
157
+ private getNavigationDirection(key: string): 1 | -1 | undefined {
158
+ if (key === Keys.ArrowRight || key === Keys.ArrowDown) {
159
+ return 1;
160
+ }
161
+
162
+ if (key === Keys.ArrowLeft || key === Keys.ArrowUp) {
163
+ return -1;
164
+ }
165
+
166
+ return undefined;
167
+ }
168
+
169
+ private dispatchValueEvent(type: 'input' | 'change'): void {
170
+ this.element.dispatchEvent(new Event(type, { bubbles: true }));
171
+ }
172
+
173
+ private findError(error: IError): IError | undefined {
174
+ for (const existing of this.errors.keys()) {
175
+ if (existing === error || existing.message === error.message) {
176
+ return existing;
177
+ }
178
+ }
179
+
180
+ return undefined;
181
+ }
182
+ }
183
+
184
+ export interface IUiRadioGroupElement extends IValidatedElement {
185
+ value: unknown;
186
+ }
187
+
188
+ function defineUiRadioGroupElementApis(element: HTMLElement) {
189
+ Object.defineProperties(element, {
190
+ tagName: {
191
+ get() {
192
+ return 'UI-RADIO-GROUP';
193
+ }
194
+ },
195
+ value: {
196
+ get(this: IUiRadioGroupElement) {
197
+ return CustomElement.for<UiRadioGroup>(this).viewModel.value;
198
+ },
199
+ set(this: IUiRadioGroupElement, value: unknown) {
200
+ CustomElement.for<UiRadioGroup>(this).viewModel.value = value;
201
+ },
202
+ configurable: true
203
+ },
204
+ disabled: {
205
+ get(this: IUiRadioGroupElement) {
206
+ return CustomElement.for<UiRadioGroup>(this).viewModel.disabled;
207
+ },
208
+ set(this: IUiRadioGroupElement, value: boolean) {
209
+ CustomElement.for<UiRadioGroup>(this).viewModel.disabled = value;
210
+ },
211
+ configurable: true
212
+ },
213
+ readOnly: {
214
+ get(this: IUiRadioGroupElement) {
215
+ return CustomElement.for<UiRadioGroup>(this).viewModel.readonly;
216
+ },
217
+ set(this: IUiRadioGroupElement, value: boolean) {
218
+ CustomElement.for<UiRadioGroup>(this).viewModel.readonly = value;
219
+ },
220
+ configurable: true
221
+ },
222
+ addError: {
223
+ value(this: IUiRadioGroupElement, error: IError) {
224
+ CustomElement.for<UiRadioGroup>(this).viewModel.addError(error);
225
+ },
226
+ configurable: true
227
+ },
228
+ removeError: {
229
+ value(this: IUiRadioGroupElement, error: IError) {
230
+ CustomElement.for<UiRadioGroup>(this).viewModel.removeError(error);
231
+ },
232
+ configurable: true
233
+ },
234
+ focus: {
235
+ value(this: IUiRadioGroupElement) {
236
+ CustomElement.for<UiRadioGroup>(this).viewModel.enabledRadios[0]?.element.focus();
237
+ },
238
+ configurable: true
239
+ },
240
+ blur: {
241
+ value(this: IUiRadioGroupElement) {
242
+ const viewModel = CustomElement.for<UiRadioGroup>(this).viewModel;
243
+ if (viewModel.radios.some(radio => radio.element === document.activeElement)) {
244
+ (document.activeElement as HTMLElement).blur();
245
+ }
246
+ },
247
+ configurable: true
248
+ }
249
+ });
250
+ }
@@ -0,0 +1,11 @@
1
+ <template class="ui-radio"
2
+ role="radio"
3
+ tabindex.bind="parentGroup.disabled || disabled ? -1 : 0"
4
+ aria-checked.attr="parentGroup.value === value ? 'true' : 'false'"
5
+ aria-disabled.attr="disabled || parentGroup.disabled ? '' : null"
6
+ data-selected.attr="parentGroup.value === value ? '' : null"
7
+ data-disabled.attr="disabled || parentGroup.disabled ? '' : null"
8
+ click.trigger="onClick()">
9
+ <span class="ui-radio__indicator" aria-hidden="true"></span>
10
+ <span class="ui-radio__label"><au-slot></au-slot></span>
11
+ </template>
@@ -0,0 +1,35 @@
1
+ import { bindable, customElement, INode, resolve } from 'aurelia';
2
+ import { booleanAttr } from '../base/boolean-attr';
3
+ import { UiRadioGroup } from './ui-radio-group';
4
+ import template from './ui-radio.html?raw';
5
+
6
+ @customElement({ name: 'ui-radio', template })
7
+ export class UiRadio {
8
+ readonly element = resolve(INode) as HTMLElement;
9
+ readonly parentGroup = resolve(UiRadioGroup);
10
+
11
+ private readonly onHostKeyDown = (event: KeyboardEvent): void => {
12
+ this.parentGroup.onRadioKeyDown(this, event);
13
+ };
14
+
15
+ @bindable
16
+ value: unknown = this;
17
+
18
+ @bindable({ set: booleanAttr })
19
+ disabled: boolean = false;
20
+
21
+ onClick(): void {
22
+ if (!this.disabled) {
23
+ this.parentGroup.select(this.value);
24
+ }
25
+ }
26
+
27
+ attaching(): void {
28
+ this.element.addEventListener('keydown', this.onHostKeyDown);
29
+ }
30
+
31
+ detaching(): void {
32
+ this.element.removeEventListener('keydown', this.onHostKeyDown);
33
+ }
34
+
35
+ }
@@ -0,0 +1,4 @@
1
+ declare module '*.html?raw' {
2
+ const template: string;
3
+ export default template;
4
+ }
@@ -0,0 +1,10 @@
1
+ <template class="ui-segment"
2
+ role="radio"
3
+ tabindex.bind="parentControl.disabled || disabled ? -1 : parentControl.value === value ? 0 : -1"
4
+ aria-checked.attr="parentControl.value === value ? 'true' : 'false'"
5
+ aria-disabled.attr="parentControl.disabled || disabled ? '' : null"
6
+ data-selected.attr="parentControl.value === value ? '' : null"
7
+ data-disabled.attr="parentControl.disabled || disabled ? '' : null"
8
+ click.trigger="onClick()">
9
+ <au-slot></au-slot>
10
+ </template>
@@ -0,0 +1,20 @@
1
+ import { bindable, customElement, INode, resolve } from 'aurelia';
2
+ import { booleanAttr } from '../base/boolean-attr';
3
+ import { UiSegmentedControl } from './ui-segmented-control';
4
+ import template from './ui-segment.html?raw';
5
+
6
+ @customElement({ name: 'ui-segment', template })
7
+ export class UiSegment {
8
+ readonly element = resolve(INode) as HTMLElement;
9
+ readonly parentControl = resolve(UiSegmentedControl);
10
+
11
+ @bindable
12
+ value: unknown = this;
13
+
14
+ @bindable({ set: booleanAttr })
15
+ disabled: boolean = false;
16
+
17
+ onClick(): void {
18
+ this.parentControl.select(this);
19
+ }
20
+ }
@@ -0,0 +1,9 @@
1
+ <template class="ui-segmented-control"
2
+ role="radiogroup"
3
+ aria-label.attr="label || null"
4
+ aria-disabled.attr="disabled ? '' : null"
5
+ data-disabled.attr="disabled ? '' : null"
6
+ data-readonly.attr="readonly ? '' : null"
7
+ keydown.trigger="onKeyDown($event)">
8
+ <au-slot></au-slot>
9
+ </template>
@@ -0,0 +1,119 @@
1
+ import { bindable, BindingMode, children, customElement, INode, resolve } from 'aurelia';
2
+ import { booleanAttr } from '../base/boolean-attr';
3
+ import { Keys } from '../base/keys';
4
+ import { UiSegment } from './ui-segment';
5
+ import template from './ui-segmented-control.html?raw';
6
+
7
+ @customElement({ name: 'ui-segmented-control', template })
8
+ export class UiSegmentedControl {
9
+ private readonly host = resolve(INode) as HTMLElement;
10
+
11
+ @bindable({ mode: BindingMode.twoWay })
12
+ value: unknown;
13
+
14
+ @bindable
15
+ label: string | undefined;
16
+
17
+ @bindable({ set: booleanAttr })
18
+ disabled: boolean = false;
19
+
20
+ @bindable({ set: booleanAttr })
21
+ readonly: boolean = false;
22
+
23
+ @children({
24
+ query: 'ui-segment',
25
+ map: (_node, viewModel) => viewModel
26
+ })
27
+ segments: UiSegment[] = [];
28
+ segmentsChanged(): void {
29
+ this.selectInitialSegment();
30
+ }
31
+
32
+ attached(): void {
33
+ this.selectInitialSegment();
34
+ }
35
+
36
+ select(segment: UiSegment): void {
37
+ if (this.disabled || this.readonly || segment.disabled || this.value === segment.value) {
38
+ return;
39
+ }
40
+
41
+ this.value = segment.value;
42
+ this.dispatchValueEvent('input');
43
+ this.dispatchValueEvent('change');
44
+ }
45
+
46
+ onKeyDown(event: KeyboardEvent): void {
47
+ if (this.disabled || this.readonly) {
48
+ return;
49
+ }
50
+
51
+ const active = this.segments.find(segment => segment.element === event.target);
52
+ if (!active) {
53
+ return;
54
+ }
55
+
56
+ if (event.key === Keys.Space || event.key === Keys.Enter) {
57
+ event.preventDefault();
58
+ this.select(active);
59
+ return;
60
+ }
61
+
62
+ const segments = this.enabledSegments;
63
+ if (!segments.length) {
64
+ return;
65
+ }
66
+
67
+ if (event.key === Keys.Home) {
68
+ event.preventDefault();
69
+ segments[0].element.focus();
70
+ return;
71
+ }
72
+
73
+ if (event.key === Keys.End) {
74
+ event.preventDefault();
75
+ segments[segments.length - 1].element.focus();
76
+ return;
77
+ }
78
+
79
+ const direction = this.getNavigationDirection(event.key);
80
+ if (!direction) {
81
+ return;
82
+ }
83
+
84
+ event.preventDefault();
85
+ const index = segments.indexOf(active);
86
+ segments[(index + direction + segments.length) % segments.length].element.focus();
87
+ }
88
+
89
+ get enabledSegments(): UiSegment[] {
90
+ return this.segments.filter(segment => !segment.disabled);
91
+ }
92
+
93
+ private selectInitialSegment(): void {
94
+ if (this.value !== undefined) {
95
+ return;
96
+ }
97
+
98
+ const first = this.enabledSegments[0];
99
+ if (first) {
100
+ this.value = first.value;
101
+ }
102
+ }
103
+
104
+ private getNavigationDirection(key: string): 1 | -1 | undefined {
105
+ if (key === Keys.ArrowRight || key === Keys.ArrowDown) {
106
+ return 1;
107
+ }
108
+
109
+ if (key === Keys.ArrowLeft || key === Keys.ArrowUp) {
110
+ return -1;
111
+ }
112
+
113
+ return undefined;
114
+ }
115
+
116
+ private dispatchValueEvent(type: 'input' | 'change'): void {
117
+ this.host.dispatchEvent(new Event(type, { bubbles: true }));
118
+ }
119
+ }
@@ -0,0 +1,10 @@
1
+ import { templateCompilerHooks } from 'aurelia';
2
+
3
+ @templateCompilerHooks
4
+ export class EnhanceUiSelect {
5
+ compiling(template: HTMLElement | HTMLTemplateElement) {
6
+ template.innerHTML = template.innerHTML
7
+ .replaceAll('<ui-select ', '<label as-element="ui-select" ui-select-element ')
8
+ .replaceAll('</ui-select>', '</label>');
9
+ }
10
+ }
@@ -0,0 +1,70 @@
1
+ <template class="ui-select"
2
+ data-disabled.attr="disabled ? '' : null"
3
+ data-invalid.attr="invalid || errors.size ? '' : null"
4
+ data-focus.attr="focus ? '' : null"
5
+ data-active.attr="active ? '' : null"
6
+ data-open.attr="open ? '' : null"
7
+ data-inset.attr="inset ? '' : null"
8
+ data-has-value.attr="hasValue ? '' : null">
9
+ <label class="ui-select__label"
10
+ for.bind="id"
11
+ id.bind="!inset && label ? labelId : null"
12
+ show.bind="label && !inset">${label}</label>
13
+
14
+ <div class="ui-select__control"
15
+ ref="controlEl"
16
+ id.bind="id"
17
+ role="button"
18
+ tabindex.bind="disabled ? -1 : 0"
19
+ aria-haspopup="listbox"
20
+ aria-expanded.attr="open ? 'true' : 'false'"
21
+ aria-labelledby.bind="label ? labelId : null"
22
+ aria-invalid.bind="invalid || errors.size ? 'true' : 'false'"
23
+ aria-describedby.bind="errors.size ? errorsId : (helperNodes.length ? helperId : null)"
24
+ aria-disabled.attr="disabled ? '' : null"
25
+ aria-required.attr="required ? 'true' : null"
26
+ click.trigger="onClick()"
27
+ keydown.trigger="onKeyDown($event)"
28
+ focusin.trigger="onFocusIn()"
29
+ focusout.trigger="onFocusOut($event)"
30
+ pointerdown.trigger="onPointerDown()"
31
+ pointerup.trigger="onPointerUp()"
32
+ pointerleave.trigger="onPointerLeave()">
33
+ <span class="ui-select__leading" show.bind="leadingNodes.length">
34
+ <au-slot name="leading"></au-slot>
35
+ </span>
36
+
37
+ <span class="ui-select__inset-label"
38
+ id.bind="inset && label ? labelId : null"
39
+ show.bind="label && inset">${label}</span>
40
+
41
+ <span class="ui-select__value" data-placeholder.attr="displayText ? null : ''">
42
+ ${displayText || placeholderText}
43
+ </span>
44
+
45
+ <span class="ui-select__trailing">
46
+ <au-slot name="trailing">
47
+ <span class="ui-select__chevron" aria-hidden="true"></span>
48
+ </au-slot>
49
+ </span>
50
+ </div>
51
+
52
+ <ui-menu open.bind="open"
53
+ anchor.bind="controlEl"
54
+ tab-reference.bind="controlEl"
55
+ match-anchor-width
56
+ menu-tab-away.trigger="onMenuTabAway()"
57
+ menu-select.trigger="onMenuSelect($event)">
58
+ <au-slot></au-slot>
59
+ </ui-menu>
60
+
61
+ <div class="ui-select__subscript" show.bind="errors.size || helperText || helperNodes.length">
62
+ <div class="ui-select__helper" id.bind="helperId" show.bind="!errors.size && (helperText || helperNodes.length)">
63
+ <au-slot name="helper">${helperText}</au-slot>
64
+ </div>
65
+
66
+ <div class="ui-select__errors" id.bind="errorsId" show.bind="errors.size">
67
+ <div class="ui-select__error" repeat.for="[error, _] of errors" if.bind="error.message">${error.message}</div>
68
+ </div>
69
+ </div>
70
+ </template>