@dubai-design-system/components-js 3.12.16 → 5.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 (263) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/dist/cjs/dda-accordion.cjs.entry.js +4 -4
  3. package/dist/cjs/dda-alert.cjs.entry.js +11 -4
  4. package/dist/cjs/dda-attach-file.cjs.entry.js +19 -4
  5. package/dist/cjs/dda-avatar.cjs.entry.js +12 -6
  6. package/dist/cjs/dda-banner.cjs.entry.js +2 -2
  7. package/dist/cjs/dda-breadcrumb.cjs.entry.js +2 -2
  8. package/dist/cjs/dda-button.cjs.entry.js +3 -3
  9. package/dist/cjs/dda-checkbox.cjs.entry.js +2 -2
  10. package/dist/cjs/dda-chip.cjs.entry.js +4 -4
  11. package/dist/cjs/dda-credit-card.cjs.entry.js +3 -3
  12. package/dist/cjs/dda-creditcard-field.cjs.entry.js +22 -4
  13. package/dist/cjs/dda-dropdown.cjs.entry.js +3 -3
  14. package/dist/cjs/dda-footer.cjs.entry.js +5 -3
  15. package/dist/cjs/dda-header.cjs.entry.js +3 -3
  16. package/dist/cjs/dda-home-banner.cjs.entry.js +172 -13
  17. package/dist/cjs/dda-horizontal-stepper.cjs.entry.js +4 -4
  18. package/dist/cjs/dda-input.cjs.entry.js +21 -4
  19. package/dist/cjs/dda-link-button_2.cjs.entry.js +7 -7
  20. package/dist/cjs/dda-number-field.cjs.entry.js +19 -4
  21. package/dist/cjs/dda-pagination.cjs.entry.js +4 -4
  22. package/dist/cjs/dda-phonefield.cjs.entry.js +22 -4
  23. package/dist/cjs/dda-progressbar.cjs.entry.js +5 -4
  24. package/dist/cjs/dda-range-slider.cjs.entry.js +4 -4
  25. package/dist/cjs/dda-search-input.cjs.entry.js +23 -6
  26. package/dist/cjs/dda-segmented-tabs.cjs.entry.js +30 -5
  27. package/dist/cjs/dda-select.cjs.entry.js +114 -5
  28. package/dist/cjs/dda-sticky-footer.cjs.entry.js +5 -3
  29. package/dist/cjs/dda-tabs.cjs.entry.js +3 -3
  30. package/dist/cjs/dda-textarea.cjs.entry.js +74 -5
  31. package/dist/cjs/dda-toggle.cjs.entry.js +3 -3
  32. package/dist/cjs/dda-tooltip.cjs.entry.js +29 -4
  33. package/dist/cjs/dda-ui-card.cjs.entry.js +2 -2
  34. package/dist/cjs/dda-vertical-stepper.cjs.entry.js +2 -2
  35. package/dist/cjs/dda.cjs.js +3 -4
  36. package/dist/cjs/index-DGHrEPBX.js +1986 -0
  37. package/dist/cjs/loader.cjs.js +3 -4
  38. package/dist/collection/components/dda-accordion/dda-accordion.css +10 -0
  39. package/dist/collection/components/dda-accordion/dda-accordion.js +1 -1
  40. package/dist/collection/components/dda-alert/dda-alert.js +8 -1
  41. package/dist/collection/components/dda-attach-file/dda-attach-file.js +16 -1
  42. package/dist/collection/components/dda-avatar/dda-avatar.css +25 -1
  43. package/dist/collection/components/dda-avatar/dda-avatar.js +8 -2
  44. package/dist/collection/components/dda-chip/dda-chip.css +14 -1
  45. package/dist/collection/components/dda-chip/dda-chip.js +1 -1
  46. package/dist/collection/components/dda-credit-card/dda-credit-card.css +8 -2
  47. package/dist/collection/components/dda-creditcard-field/dda-creditcard-field.js +39 -1
  48. package/dist/collection/components/dda-creditcard-field/dda-creditcard-field.stories.js +9 -0
  49. package/dist/collection/components/dda-footer/dda-footer.js +3 -4
  50. package/dist/collection/components/dda-header/dda-header.css +36 -0
  51. package/dist/collection/components/dda-header/dda-header.js +1 -1
  52. package/dist/collection/components/dda-home-banner/dda-home-banner.js +358 -11
  53. package/dist/collection/components/dda-home-banner/dda-home-banner.stories.js +79 -49
  54. package/dist/collection/components/dda-home-banner/home-banner.css +45 -4
  55. package/dist/collection/components/dda-input/dda-input.js +18 -1
  56. package/dist/collection/components/dda-link-button/dda-link-button.js +2 -2
  57. package/dist/collection/components/dda-number-field/dda-number-field.js +16 -1
  58. package/dist/collection/components/dda-pagination/dda-pagination.css +9 -1
  59. package/dist/collection/components/dda-pagination/dda-pagination.js +1 -1
  60. package/dist/collection/components/dda-phonefield/dda-phonefield.js +39 -1
  61. package/dist/collection/components/dda-phonefield/dda-phonefield.stories.js +11 -1
  62. package/dist/collection/components/dda-progressbar/dda-progressbar.css +4 -0
  63. package/dist/collection/components/dda-progressbar/dda-progressbar.js +22 -1
  64. package/dist/collection/components/dda-progressbar/dda-progressbar.stories.js +6 -0
  65. package/dist/collection/components/dda-radiobutton/dda-radiobutton.css +26 -2
  66. package/dist/collection/components/dda-radiobutton/dda-radiobutton.js +1 -1
  67. package/dist/collection/components/dda-range-slider/dda-range-slider.css +18 -2
  68. package/dist/collection/components/dda-range-slider/dda-range-slider.js +2 -2
  69. package/dist/collection/components/dda-search-input/dda-search-input.js +38 -2
  70. package/dist/collection/components/dda-search-input/dda-search-input.stories.js +9 -0
  71. package/dist/collection/components/dda-select/dda-select.js +113 -2
  72. package/dist/collection/components/dda-sticky-footer/dda-sticky-footer.js +3 -4
  73. package/dist/collection/components/dda-tabs/dda-tabs.js +1 -1
  74. package/dist/collection/components/dda-textarea/dda-textarea.js +71 -2
  75. package/dist/collection/components/dda-toggle/dda-toggle.js +1 -1
  76. package/dist/collection/components/dda-tooltip/dda-tooltip.css +17 -1
  77. package/dist/collection/components/dda-tooltip/dda-tooltip.js +31 -1
  78. package/dist/collection/components/dda-ui-card/dda-ui-card.js +1 -1
  79. package/dist/collection/components/segmented-groups/dda-segmented-tabs/dda-segmented-tabs.js +89 -3
  80. package/dist/collection/components/segmented-groups/dda-segmented-tabs/dda-segmented-tabs.stories.js +21 -1
  81. package/dist/collection/components/stepper/dda-horizontal-stepper/dda-horizontal-stepper.css +15 -3
  82. package/dist/collection/components/stepper/dda-horizontal-stepper/dda-horizontal-stepper.js +1 -1
  83. package/dist/collection/components/stepper/dda-vertical-stepper/dda-vertical-stepper.js +1 -1
  84. package/dist/collection/global/dda-button.css +49 -18
  85. package/dist/collection/global/global.css +26 -2
  86. package/dist/collection/global/input.css +69 -8
  87. package/dist/collection/utils/contrast.js +38 -0
  88. package/dist/components/dda-accordion.js +1 -1
  89. package/dist/components/dda-alert.js +1 -1
  90. package/dist/components/dda-attach-file.js +1 -1
  91. package/dist/components/dda-avatar.js +1 -1
  92. package/dist/components/dda-banner.js +1 -1
  93. package/dist/components/dda-breadcrumb.js +1 -1
  94. package/dist/components/dda-button.js +1 -1
  95. package/dist/components/dda-checkbox.js +1 -1
  96. package/dist/components/dda-chip.js +1 -1
  97. package/dist/components/dda-credit-card.js +1 -1
  98. package/dist/components/dda-creditcard-field.js +1 -1
  99. package/dist/components/dda-dropdown.js +1 -1
  100. package/dist/components/dda-footer.js +1 -1
  101. package/dist/components/dda-header.js +1 -1
  102. package/dist/components/dda-home-banner.js +1 -1
  103. package/dist/components/dda-horizontal-stepper.js +1 -1
  104. package/dist/components/dda-input.js +1 -1
  105. package/dist/components/dda-link-button.js +1 -1
  106. package/dist/components/dda-number-field.js +1 -1
  107. package/dist/components/dda-pagination.js +1 -1
  108. package/dist/components/dda-phonefield.js +1 -1
  109. package/dist/components/dda-progressbar.js +1 -1
  110. package/dist/components/dda-radiobutton.js +1 -1
  111. package/dist/components/dda-range-slider.js +1 -1
  112. package/dist/components/dda-search-input.js +1 -1
  113. package/dist/components/dda-segmented-tabs.js +1 -1
  114. package/dist/components/dda-select.js +1 -1
  115. package/dist/components/dda-sticky-footer.js +1 -1
  116. package/dist/components/dda-tabs.js +1 -1
  117. package/dist/components/dda-textarea.js +1 -1
  118. package/dist/components/dda-toggle.js +1 -1
  119. package/dist/components/dda-tooltip.js +1 -1
  120. package/dist/components/dda-ui-card.js +1 -1
  121. package/dist/components/dda-vertical-stepper.js +1 -1
  122. package/dist/components/index.js +1 -1
  123. package/dist/components/p-BaW1ewxd.js +1 -0
  124. package/dist/components/p-C2ufT7tL.js +1 -0
  125. package/dist/components/p-CbUih1OY.js +1 -0
  126. package/dist/components/p-Cgvws3Uk.js +1 -0
  127. package/dist/components/p-HakkUtRK.js +1 -0
  128. package/dist/dda/dda.css +20 -0
  129. package/dist/dda/dda.esm.js +1 -1
  130. package/dist/dda/p-0b56fbcb.entry.js +1 -0
  131. package/dist/dda/p-1df4494d.entry.js +1 -0
  132. package/dist/dda/p-207c4034.entry.js +1 -0
  133. package/dist/dda/p-23c6a709.entry.js +1 -0
  134. package/dist/dda/p-2c0f4e9e.entry.js +1 -0
  135. package/dist/dda/p-2e4e47ec.entry.js +1 -0
  136. package/dist/dda/p-3b9a784a.entry.js +1 -0
  137. package/dist/dda/p-4400194a.entry.js +1 -0
  138. package/dist/dda/p-48f14688.entry.js +1 -0
  139. package/dist/dda/p-4aef15b0.entry.js +1 -0
  140. package/dist/dda/{p-0db613dc.entry.js → p-5d0b1fea.entry.js} +1 -1
  141. package/dist/dda/p-6150d6ca.entry.js +1 -0
  142. package/dist/dda/p-6def14a1.entry.js +1 -0
  143. package/dist/dda/p-7c8b1191.entry.js +1 -0
  144. package/dist/dda/p-7eb8942f.entry.js +1 -0
  145. package/dist/dda/p-82dc3344.entry.js +1 -0
  146. package/dist/dda/p-88c5aa03.entry.js +1 -0
  147. package/dist/dda/{p-872e0f49.entry.js → p-8bbd3b3b.entry.js} +1 -1
  148. package/dist/dda/p-96aaf2c6.entry.js +1 -0
  149. package/dist/dda/p-99e59635.entry.js +1 -0
  150. package/dist/dda/p-CfK_KUZU.js +2 -0
  151. package/dist/dda/p-b6096645.entry.js +1 -0
  152. package/dist/dda/p-b68b2d3a.entry.js +1 -0
  153. package/dist/dda/p-c39fc443.entry.js +1 -0
  154. package/dist/dda/p-cf6c7bc5.entry.js +1 -0
  155. package/dist/dda/p-d096ea61.entry.js +1 -0
  156. package/dist/dda/p-d5274874.entry.js +1 -0
  157. package/dist/dda/p-d606adfc.entry.js +1 -0
  158. package/dist/dda/p-da82dc4c.entry.js +1 -0
  159. package/dist/dda/p-dc72bfd8.entry.js +1 -0
  160. package/dist/dda/p-dec1b61c.entry.js +1 -0
  161. package/dist/dda/p-eb2d0c46.entry.js +1 -0
  162. package/dist/dda/p-f9c681e4.entry.js +1 -0
  163. package/dist/dda/p-fd637136.entry.js +1 -0
  164. package/dist/esm/dda-accordion.entry.js +4 -4
  165. package/dist/esm/dda-alert.entry.js +11 -4
  166. package/dist/esm/dda-attach-file.entry.js +19 -4
  167. package/dist/esm/dda-avatar.entry.js +12 -6
  168. package/dist/esm/dda-banner.entry.js +2 -2
  169. package/dist/esm/dda-breadcrumb.entry.js +2 -2
  170. package/dist/esm/dda-button.entry.js +3 -3
  171. package/dist/esm/dda-checkbox.entry.js +2 -2
  172. package/dist/esm/dda-chip.entry.js +4 -4
  173. package/dist/esm/dda-credit-card.entry.js +3 -3
  174. package/dist/esm/dda-creditcard-field.entry.js +22 -4
  175. package/dist/esm/dda-dropdown.entry.js +3 -3
  176. package/dist/esm/dda-footer.entry.js +5 -3
  177. package/dist/esm/dda-header.entry.js +3 -3
  178. package/dist/esm/dda-home-banner.entry.js +172 -13
  179. package/dist/esm/dda-horizontal-stepper.entry.js +4 -4
  180. package/dist/esm/dda-input.entry.js +21 -4
  181. package/dist/esm/dda-link-button_2.entry.js +7 -7
  182. package/dist/esm/dda-number-field.entry.js +19 -4
  183. package/dist/esm/dda-pagination.entry.js +4 -4
  184. package/dist/esm/dda-phonefield.entry.js +22 -4
  185. package/dist/esm/dda-progressbar.entry.js +5 -4
  186. package/dist/esm/dda-range-slider.entry.js +4 -4
  187. package/dist/esm/dda-search-input.entry.js +23 -6
  188. package/dist/esm/dda-segmented-tabs.entry.js +30 -5
  189. package/dist/esm/dda-select.entry.js +114 -5
  190. package/dist/esm/dda-sticky-footer.entry.js +5 -3
  191. package/dist/esm/dda-tabs.entry.js +3 -3
  192. package/dist/esm/dda-textarea.entry.js +74 -5
  193. package/dist/esm/dda-toggle.entry.js +3 -3
  194. package/dist/esm/dda-tooltip.entry.js +29 -4
  195. package/dist/esm/dda-ui-card.entry.js +2 -2
  196. package/dist/esm/dda-vertical-stepper.entry.js +2 -2
  197. package/dist/esm/dda.js +3 -4
  198. package/dist/esm/index-CfK_KUZU.js +1976 -0
  199. package/dist/esm/loader.js +3 -4
  200. package/dist/types/components/dda-alert/dda-alert.d.ts +1 -0
  201. package/dist/types/components/dda-attach-file/dda-attach-file.d.ts +3 -0
  202. package/dist/types/components/dda-creditcard-field/dda-creditcard-field.d.ts +4 -0
  203. package/dist/types/components/dda-creditcard-field/dda-creditcard-field.stories.d.ts +6 -0
  204. package/dist/types/components/dda-home-banner/dda-home-banner.d.ts +46 -1
  205. package/dist/types/components/dda-home-banner/dda-home-banner.stories.d.ts +27 -3
  206. package/dist/types/components/dda-input/dda-input.d.ts +3 -0
  207. package/dist/types/components/dda-number-field/dda-number-field.d.ts +3 -0
  208. package/dist/types/components/dda-phonefield/dda-phonefield.d.ts +4 -0
  209. package/dist/types/components/dda-phonefield/dda-phonefield.stories.d.ts +6 -0
  210. package/dist/types/components/dda-progressbar/dda-progressbar.d.ts +1 -0
  211. package/dist/types/components/dda-progressbar/dda-progressbar.stories.d.ts +7 -0
  212. package/dist/types/components/dda-search-input/dda-search-input.d.ts +4 -0
  213. package/dist/types/components/dda-search-input/dda-search-input.stories.d.ts +6 -0
  214. package/dist/types/components/dda-select/dda-select.d.ts +13 -0
  215. package/dist/types/components/dda-textarea/dda-textarea.d.ts +6 -0
  216. package/dist/types/components/dda-tooltip/dda-tooltip.d.ts +6 -0
  217. package/dist/types/components/segmented-groups/dda-segmented-tabs/dda-segmented-tabs.d.ts +12 -0
  218. package/dist/types/components/segmented-groups/dda-segmented-tabs/dda-segmented-tabs.stories.d.ts +12 -0
  219. package/dist/types/components.d.ts +171 -1
  220. package/dist/types/utils/contrast.d.ts +19 -0
  221. package/package.json +23 -6
  222. package/dist/cjs/app-globals-V2Kpy_OQ.js +0 -5
  223. package/dist/cjs/index-B79qki6G.js +0 -1975
  224. package/dist/components/p-BId7flZ3.js +0 -1
  225. package/dist/components/p-BvP8lGT3.js +0 -1
  226. package/dist/components/p-CAZwi69K.js +0 -1
  227. package/dist/components/p-DlU_OvNg.js +0 -1
  228. package/dist/components/p-DywjKcXy.js +0 -1
  229. package/dist/dda/p-01b5288e.entry.js +0 -1
  230. package/dist/dda/p-05909550.entry.js +0 -1
  231. package/dist/dda/p-290878ba.entry.js +0 -1
  232. package/dist/dda/p-2a027297.entry.js +0 -1
  233. package/dist/dda/p-2be2258d.entry.js +0 -1
  234. package/dist/dda/p-320daf89.entry.js +0 -1
  235. package/dist/dda/p-3b5501d5.entry.js +0 -1
  236. package/dist/dda/p-41d48ef1.entry.js +0 -1
  237. package/dist/dda/p-49efa7b5.entry.js +0 -1
  238. package/dist/dda/p-4d544d34.entry.js +0 -1
  239. package/dist/dda/p-5a8d0718.entry.js +0 -1
  240. package/dist/dda/p-687993df.entry.js +0 -1
  241. package/dist/dda/p-72cf45ff.entry.js +0 -1
  242. package/dist/dda/p-74136148.entry.js +0 -1
  243. package/dist/dda/p-7b9a03b8.entry.js +0 -1
  244. package/dist/dda/p-813378ca.entry.js +0 -1
  245. package/dist/dda/p-81e2a31e.entry.js +0 -1
  246. package/dist/dda/p-9ada3a28.entry.js +0 -1
  247. package/dist/dda/p-9bb057e8.entry.js +0 -1
  248. package/dist/dda/p-9eb37a5b.entry.js +0 -1
  249. package/dist/dda/p-CnOk80gh.js +0 -2
  250. package/dist/dda/p-DQuL1Twl.js +0 -1
  251. package/dist/dda/p-ad2eb016.entry.js +0 -1
  252. package/dist/dda/p-bd34eb45.entry.js +0 -1
  253. package/dist/dda/p-d8b2f59d.entry.js +0 -1
  254. package/dist/dda/p-da8e1d19.entry.js +0 -1
  255. package/dist/dda/p-dd16275a.entry.js +0 -1
  256. package/dist/dda/p-de5a5f95.entry.js +0 -1
  257. package/dist/dda/p-e3c3c3c8.entry.js +0 -1
  258. package/dist/dda/p-ebaf8588.entry.js +0 -1
  259. package/dist/dda/p-efdf9aba.entry.js +0 -1
  260. package/dist/dda/p-f135fada.entry.js +0 -1
  261. package/dist/dda/p-f3a93726.entry.js +0 -1
  262. package/dist/esm/app-globals-DQuL1Twl.js +0 -3
  263. package/dist/esm/index-CnOk80gh.js +0 -1966
@@ -1,15 +1,39 @@
1
1
  import { h } from "@stencil/core";
2
2
  export class DdaSegmentedTabs {
3
3
  constructor() {
4
+ /** Index of the segment selected by default. Clamped to a valid item index. */
5
+ this.selected_index = 0;
6
+ /** F-004 repair: the currently-selected segment. Exactly one segment is
7
+ * selected at a time; this is what makes the component interactive at all. */
8
+ this.active_index = 0;
4
9
  this.parsedItems = [];
5
10
  }
6
11
  componentWillLoad() {
7
12
  this.parsedItems = JSON.parse(this.items);
13
+ this.active_index = this.clampIndex(this.selected_index);
14
+ }
15
+ clampIndex(index) {
16
+ if (!Array.isArray(this.parsedItems) || this.parsedItems.length === 0) {
17
+ return 0;
18
+ }
19
+ if (typeof index !== 'number' || index < 0 || index >= this.parsedItems.length) {
20
+ return 0;
21
+ }
22
+ return index;
23
+ }
24
+ selectSegment(index) {
25
+ if (index === this.active_index) {
26
+ return;
27
+ }
28
+ this.active_index = index;
29
+ this.segmentChange.emit(index);
8
30
  }
9
31
  render() {
10
- return (h("div", { key: 'e0189026efbabcdfae9ccef7050705bf645bf33a', class: `dda-segmented-group ${this.custom_class} ${this.radius_type} ${this.component_mode}` }, this.parsedItems.map(item => (item.startsWith('fo') ?
11
- h("button", { name: this.button_name, class: "dda-segmented-item" }, h("i", { class: "material-icons material-symbols-outlined" }, item)) :
12
- h("button", { name: this.button_name, class: "dda-segmented-item" }, item)))));
32
+ return (h("div", { key: '83b176643df1781211b5ec722d0c057002c6bc72', role: "group", "aria-label": this.aria_label, class: `dda-segmented-group ${this.custom_class} ${this.radius_type} ${this.component_mode}` }, this.parsedItems.map((item, index) => {
33
+ const isSelected = index === this.active_index;
34
+ const className = `dda-segmented-item${isSelected ? ' active' : ''}`;
35
+ return item.startsWith('fo') ? (h("button", { name: this.button_name, type: "button", class: className, "aria-pressed": isSelected ? 'true' : 'false', onClick: () => this.selectSegment(index) }, h("i", { class: "material-icons material-symbols-outlined" }, item))) : (h("button", { name: this.button_name, type: "button", class: className, "aria-pressed": isSelected ? 'true' : 'false', onClick: () => this.selectSegment(index) }, item));
36
+ })));
13
37
  }
14
38
  static get is() { return "dda-segmented-tabs"; }
15
39
  static get originalStyleUrls() {
@@ -118,7 +142,69 @@ export class DdaSegmentedTabs {
118
142
  "setter": false,
119
143
  "reflect": false,
120
144
  "attribute": "button_name"
145
+ },
146
+ "aria_label": {
147
+ "type": "string",
148
+ "mutable": false,
149
+ "complexType": {
150
+ "original": "string",
151
+ "resolved": "string",
152
+ "references": {}
153
+ },
154
+ "required": false,
155
+ "optional": false,
156
+ "docs": {
157
+ "tags": [],
158
+ "text": "Accessible name for the group (applied as aria-label on the group container)."
159
+ },
160
+ "getter": false,
161
+ "setter": false,
162
+ "reflect": false,
163
+ "attribute": "aria_label"
164
+ },
165
+ "selected_index": {
166
+ "type": "number",
167
+ "mutable": false,
168
+ "complexType": {
169
+ "original": "number",
170
+ "resolved": "number",
171
+ "references": {}
172
+ },
173
+ "required": false,
174
+ "optional": false,
175
+ "docs": {
176
+ "tags": [],
177
+ "text": "Index of the segment selected by default. Clamped to a valid item index."
178
+ },
179
+ "getter": false,
180
+ "setter": false,
181
+ "reflect": false,
182
+ "attribute": "selected_index",
183
+ "defaultValue": "0"
121
184
  }
122
185
  };
123
186
  }
187
+ static get states() {
188
+ return {
189
+ "active_index": {}
190
+ };
191
+ }
192
+ static get events() {
193
+ return [{
194
+ "method": "segmentChange",
195
+ "name": "segmentChange",
196
+ "bubbles": true,
197
+ "cancelable": true,
198
+ "composed": true,
199
+ "docs": {
200
+ "tags": [],
201
+ "text": "Emits the newly-selected index whenever the selection changes."
202
+ },
203
+ "complexType": {
204
+ "original": "number",
205
+ "resolved": "number",
206
+ "references": {}
207
+ }
208
+ }];
209
+ }
124
210
  }
@@ -23,12 +23,26 @@ export default {
23
23
  button_name: {
24
24
  control: { type: 'text' },
25
25
  description: 'Button name',
26
- }
26
+ },
27
+ aria_label: {
28
+ control: { type: 'text' },
29
+ description: 'Accessible name for the group (applied as aria-label on the role="group" container)',
30
+ },
31
+ selected_index: {
32
+ control: { type: 'number' },
33
+ description: 'Index of the segment selected by default (clamped to a valid item index; defaults to 0)',
34
+ },
27
35
  },
28
36
  parameters: {
29
37
  docs: {
30
38
  description: {
31
39
  component: `
40
+ Exactly one segment is selected at a time. Clicking a segment, or focusing it with
41
+ Tab and activating it with Enter or Space, selects it and fires \`segmentChange\`
42
+ with the newly-selected index. This is a group of mutually-exclusive toggle
43
+ buttons (\`role="group"\` + \`aria-pressed\`), not the WAI tabs pattern — it has no
44
+ associated tabpanels, so it does not claim \`role="tablist"\`/\`"tab"\`.
45
+
32
46
  To use the \`dda-segmented-tabs\` component, pass the following props:
33
47
 
34
48
  \`\`\`html
@@ -38,6 +52,8 @@ export default {
38
52
  component_mode=""
39
53
  items='["All","Recent","Saved"]'
40
54
  button_name="button_name"
55
+ aria_label="Filter results"
56
+ selected_index="0"
41
57
  ></dda-segmented-tabs>
42
58
  \`\`\`
43
59
  `,
@@ -60,6 +76,8 @@ TextItems.args = {
60
76
  custom_class: '',
61
77
  component_mode: '',
62
78
  button_name: 'button',
79
+ aria_label: 'Filter results',
80
+ selected_index: 0,
63
81
  };
64
82
  export const IconItems = Template.bind({});
65
83
  IconItems.args = {
@@ -68,4 +86,6 @@ IconItems.args = {
68
86
  custom_class: '',
69
87
  component_mode: '',
70
88
  button_name: 'button',
89
+ aria_label: 'Text alignment',
90
+ selected_index: 0,
71
91
  };
@@ -45,13 +45,17 @@
45
45
  .h-step .h-step-title {
46
46
  font-size: 14px;
47
47
  font-weight: var(--dda-fw-400);
48
- color: var(--dda-neutral-variant-30);
48
+ color: var(--dda-on-surface-variant-30);
49
49
  margin-bottom: 10px;
50
50
  }
51
51
 
52
+ .light-mode .h-step .h-step-title {
53
+ color: var(--dda-neutral-variant-30);
54
+ }
55
+
52
56
  .h-step .h-step-subtitle {
53
57
  font-size: 18px;
54
- color: var(--dda-neutral-60);
58
+ color: var(--dda-on-surface-muted);
55
59
  font-weight: var(--dda-fw-500);
56
60
  }
57
61
 
@@ -61,7 +65,7 @@
61
65
 
62
66
  .h-step .h-step-description {
63
67
  font-size: 14px;
64
- color: var(--dda-neutral-60);
68
+ color: var(--dda-on-surface-muted);
65
69
  }
66
70
 
67
71
  .h-step.completed .circle{
@@ -101,9 +105,17 @@
101
105
  }
102
106
  .h-step.completed .h-step-subtitle,
103
107
  .h-step.active .h-step-subtitle{
108
+ color: var(--dda-on-surface-0);
109
+ }
110
+ .light-mode .h-step.completed .h-step-subtitle,
111
+ .light-mode .h-step.active .h-step-subtitle{
104
112
  color: var(--dda-neutral-0);
105
113
  }
106
114
  .h-step.completed .h-step-description,
107
115
  .h-step.active .h-step-description{
116
+ color: var(--dda-on-surface-variant-30);
117
+ }
118
+ .light-mode .h-step.completed .h-step-description,
119
+ .light-mode .h-step.active .h-step-description{
108
120
  color: var(--dda-neutral-variant-30);
109
121
  }
@@ -8,7 +8,7 @@ export class DdaHorizontalStepper {
8
8
  this.parsedSteps = JSON.parse(this.steps);
9
9
  }
10
10
  render() {
11
- return (h(Host, { key: '72b17c2db0f8fbecedab6a228fe807b26ccce42b' }, h("div", { key: '613016ac02a3c302e266a3043a73e0bcb88cd41a', class: `${this.custom_class} ${this.component_mode} h-stepper-container` }, this.parsedSteps.map((step, index) => (h("div", { class: `h-step ${index === this.current_step ? 'active' : ''} ${index < this.current_step ? 'completed' : ''}` }, h("div", { class: "h-step-indicator" }, h("div", { class: "circle" })), h("div", { class: "h-step-content" }, h("div", { class: "h-step-title" }, step.title), h("div", { class: "h-step-subtitle" }, step.subtitle), h("div", { class: "h-step-description" }, step.description))))))));
11
+ return (h(Host, { key: '5b6bf0b6d79e08768c25d78f15e14bb449f3f9d4' }, h("div", { key: 'f3c2ef7bd4ae7685747fe4194b143c2fc962d3bb', class: `${this.custom_class} ${this.component_mode} h-stepper-container` }, this.parsedSteps.map((step, index) => (h("div", { class: `h-step ${index === this.current_step ? 'active' : ''} ${index < this.current_step ? 'completed' : ''}` }, h("div", { class: "h-step-indicator" }, h("div", { class: "circle" })), h("div", { class: "h-step-content" }, h("div", { class: "h-step-title" }, step.title), h("div", { class: "h-step-subtitle" }, step.subtitle), h("div", { class: "h-step-description" }, step.description))))))));
12
12
  }
13
13
  static get is() { return "dda-horizontal-stepper"; }
14
14
  static get originalStyleUrls() {
@@ -9,7 +9,7 @@ export class DdaVerticalStepper {
9
9
  this.parsedSteps = JSON.parse(this.steps);
10
10
  }
11
11
  render() {
12
- return (h(Host, { key: '7255a2449381606ddb2b225a5e84bb067b1dbfe8' }, h("div", { key: '438ad499767fe4b47aed90d0bd85652e377ddfdc', class: `${this.custom_class} ${this.component_mode} v-stepper-container` }, this.parsedSteps.map((step, index) => (h("div", { class: `v-step ${index <= this.current_Step ? 'active' : ''}` }, h("div", { class: "v-step-indicator" }, h("div", { class: "icon" }, h("i", { class: `material-icons` }, step.icon))), h("div", { class: "v-step-content" }, h("div", { class: "v-step-title" }, step.title), h("div", { class: "v-step-subtitle" }, step.subtitle), h("div", { class: "v-step-description" }, step.description)), h("div", { class: "v-step-arrow" }, h("i", { class: "material-icons material-symbols-outlined" }, "chevron_right"))))))));
12
+ return (h(Host, { key: '2cc0fba05a159beb85c51bc0d27a81a1714ad3de' }, h("div", { key: 'b9b4f452fb34f825dd30581fa976ccf183b7921f', class: `${this.custom_class} ${this.component_mode} v-stepper-container` }, this.parsedSteps.map((step, index) => (h("div", { class: `v-step ${index <= this.current_Step ? 'active' : ''}` }, h("div", { class: "v-step-indicator" }, h("div", { class: "icon" }, h("i", { class: `material-icons` }, step.icon))), h("div", { class: "v-step-content" }, h("div", { class: "v-step-title" }, step.title), h("div", { class: "v-step-subtitle" }, step.subtitle), h("div", { class: "v-step-description" }, step.description)), h("div", { class: "v-step-arrow" }, h("i", { class: "material-icons material-symbols-outlined" }, "chevron_right"))))))));
13
13
  }
14
14
  static get is() { return "dda-vertical-stepper"; }
15
15
  static get originalStyleUrls() {
@@ -12,6 +12,53 @@
12
12
  justify-content: center;
13
13
  gap: .5rem;
14
14
  }
15
+ /**
16
+ * WCAG 2.4.7/1.4.11 focus-visible repair (Task 9d: F-019, F-020, F-021).
17
+ * Every btn-color-* variant used to rely on a per-variant `:focus` rule to
18
+ * restore an indicator over the base `outline: 0` above - most attempted it
19
+ * with a malformed single-value `outline: <color>` shorthand (resets
20
+ * outline-style to its initial `none`, so nothing ever rendered - F-019),
21
+ * one variant (onsurface-primary) never attempted it at all (F-020), and
22
+ * variants with no :focus rule at all (e.g. btn-color-disabled, the
23
+ * "looks disabled but isn't" style used without the native `disabled`
24
+ * attribute) showed no change whatsoever (F-021). One rule here replaces
25
+ * all of that: a `:focus-visible`-scoped box-shadow ring, so a mouse click
26
+ * leaves no ring but Tab does. Same white+dark double-ring idiom as
27
+ * dda-home-banner's `.slider-nav *:focus-visible` (home-banner.css:182-187)
28
+ * - reused deliberately so the system has one focus-ring recipe, not one
29
+ * per component. box-shadow is not clobbered by any rule in this file, and
30
+ * a fixed white/black pair is contrast-safe against every btn-color-*
31
+ * background in both `data-theme` values by construction: for any
32
+ * background, at least one of pure white or pure black clears 3:1 against
33
+ * it (the two are complementary across the luminance range) - verified
34
+ * against every variant this task touched, see the task 9d report.
35
+ */
36
+ .dda-btn:focus-visible {
37
+ outline: none;
38
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(0, 0, 0, 0.65);
39
+ }
40
+ /**
41
+ * Deliberate exemption, not an oversight: btn-color-default-link,
42
+ * btn-color-error-link and btn-color-onsurface-link (22px tall, no
43
+ * background, no border - styled to read as inline text, not a button)
44
+ * already had a working, unbroken `outline: auto` on `:focus` (:158-160,
45
+ * 260-262, 359-361) before this task started. They were never part of
46
+ * F-019/F-020/F-021. Without this exemption the rule above would paint its
47
+ * box-shadow ring on top of that already-working outline - not a WCAG
48
+ * failure (over-indication, not under), but two different focus treatments
49
+ * inside one component family, which defeats the point of standardising on
50
+ * one idiom. A box-shadow ring reads as a filled rectangle; on a
51
+ * link-styled control with no visible button chrome at rest, that would
52
+ * change its resting silhouette into something that looks like a real
53
+ * button the instant it's focused - a worse fit than the native outline,
54
+ * which just traces the existing text. So: keep the native outline for the
55
+ * three link variants, suppress the shared ring for them specifically.
56
+ */
57
+ .btn-color-default-link:focus-visible,
58
+ .btn-color-error-link:focus-visible,
59
+ .btn-color-onsurface-link:focus-visible {
60
+ box-shadow: none;
61
+ }
15
62
  /**/
16
63
  .btn-color-default-primary{
17
64
  background-color: var(--dda-color-primary-40);
@@ -24,7 +71,6 @@
24
71
  }
25
72
  .btn-color-default-primary:focus {
26
73
  background-color: var(--dda-on-primary-variant-20);
27
- outline: var(--dda-on-primary-variant-20);
28
74
  }
29
75
  /*light*/
30
76
  .light-mode.btn-color-default-primary,
@@ -41,7 +87,6 @@
41
87
  .light-mode.btn-color-default-primary:focus,
42
88
  .light-mode .btn-color-default-primary:focus {
43
89
  background-color: var(--dda-primary-20);
44
- outline: var(--dda-primary-20);
45
90
  }
46
91
  /**/
47
92
 
@@ -57,7 +102,6 @@
57
102
  }
58
103
  .btn-color-default-secondary:focus {
59
104
  background-color: var(--dda-primary-variant-92);
60
- outline: var(--dda-primary-variant-92);
61
105
  }
62
106
  /*light*/
63
107
  .light-mode.btn-color-default-secondary {
@@ -71,7 +115,6 @@
71
115
  }
72
116
  .light-mode.btn-color-default-secondary:focus {
73
117
  background-color: var(--dda-primary-92);
74
- outline: var(--dda-primary-92);
75
118
  }
76
119
  /**/
77
120
 
@@ -130,7 +173,6 @@
130
173
  .btn-color-error-primary:focus {
131
174
  background-color: var(--dda-color-error-30);
132
175
  border: solid 1px var(--dda-color-error-30);
133
- outline: var(--dda-color-error-30);
134
176
  }
135
177
  /*light*/
136
178
  .light-mode.btn-color-error-primary {
@@ -145,7 +187,6 @@
145
187
  .light-mode.btn-color-error-primary:focus {
146
188
  background-color: var(--dda-error-30);
147
189
  border: solid 1px var(--dda-error-30);
148
- outline: var(--dda-error-30);
149
190
  }
150
191
  /**/
151
192
 
@@ -332,7 +373,6 @@
332
373
  .btn-color-secondary:focus {
333
374
  background-color: var(--dda-color-secondary-20);
334
375
  border: solid 1px var(--dda-color-secondary-20);
335
- outline: var(--dda-color-secondary-20);
336
376
  }
337
377
  /*light*/
338
378
  .light-mode.btn-color-secondary {
@@ -347,7 +387,6 @@
347
387
  .light-mode.btn-color-secondary:focus {
348
388
  background-color: var(--dda-secondary-20);
349
389
  border: solid 1px var(--dda-secondary-20);
350
- outline: var(--dda-secondary-20);
351
390
  }
352
391
  /**/
353
392
 
@@ -363,7 +402,6 @@
363
402
  .btn-color-success:focus {
364
403
  background-color: var(--dda-color-success-30);
365
404
  border: solid 1px var(--dda-color-success-30);
366
- outline: var(--dda-color-success-30);
367
405
  }
368
406
  /*light*/
369
407
  .light-mode.btn-color-success {
@@ -378,7 +416,6 @@
378
416
  .light-mode.btn-color-success:focus {
379
417
  background-color: var(--dda-success-30);
380
418
  border: solid 1px var(--dda-success-30);
381
- outline: var(--dda-success-30);
382
419
  }
383
420
  /**/
384
421
 
@@ -395,7 +432,6 @@
395
432
  .btn-color-warning:focus {
396
433
  background-color: var(--dda-color-warning-30);
397
434
  border: solid 1px var(--dda-color-warning-30);
398
- outline: var(--dda-color-warning-30);
399
435
  }
400
436
  /*light*/
401
437
  .light-mode.btn-color-warning {
@@ -411,7 +447,6 @@
411
447
  .light-mode.btn-color-warning:focus {
412
448
  background-color: var(--dda-warning-30);
413
449
  border: solid 1px var(--dda-warning-30);
414
- outline: var(--dda-warning-30);
415
450
  }
416
451
  /**/
417
452
 
@@ -427,7 +462,6 @@
427
462
  .btn-color-surface:focus {
428
463
  background-color: var(--dda-surface-92);
429
464
  border: solid 1px var(--dda-surface-92);
430
- outline: var(--dda-on-surface-20);
431
465
  }
432
466
  /*light*/
433
467
  .light-mode.btn-color-surface {
@@ -442,7 +476,6 @@
442
476
  .light-mode.btn-color-surface:focus {
443
477
  background-color: var(--dda-neutral-92);
444
478
  border: solid 1px var(--dda-neutral-92);
445
- outline: var(--dda-neutral-20);
446
479
  }
447
480
  /**/
448
481
 
@@ -458,7 +491,6 @@
458
491
  .btn-color-surface-variant:focus {
459
492
  background-color: var(--dda-on-surface-variant-20);
460
493
  border: solid 1px var(--dda-on-surface-variant-20);
461
- outline: var(--dda-on-surface-variant-20);
462
494
  }
463
495
  /*light*/
464
496
  .light-mode.btn-color-surface-variant {
@@ -473,20 +505,19 @@
473
505
  .light-mode.btn-color-surface-variant:focus {
474
506
  background-color: var(--dda-neutral-variant-20);
475
507
  border: solid 1px var(--dda-neutral-variant-20);
476
- outline: var(--dda-neutral-variant-20);
477
508
  }
478
509
  /**/
479
510
 
480
511
  .btn-color-disabled {
481
512
  background-color: var(--dda-surface-92) !important;
482
513
  border: solid 1px var(--dda-surface-92) !important;
483
- color: var(--dda-neutral-60) !important;
514
+ color: var(--dda-on-surface-muted) !important;
484
515
  cursor: not-allowed;
485
516
  }
486
517
  .light-mode.btn-color-disabled {
487
518
  background-color: var(--dda-neutral-92) !important;
488
519
  border: solid 1px var(--dda-neutral-92) !important;
489
- color: var(--dda-neutral-60) !important;
520
+ color: var(--dda-neutral-40) !important;
490
521
  cursor: not-allowed;
491
522
  }
492
523
  /**/
@@ -63,7 +63,10 @@
63
63
  --dda-on-primary-94: var(--dda-primary-20);
64
64
 
65
65
  --dda-primary-variant-96: var(--dda-primary-30);
66
- --dda-primary-variant-95: var(--dda-primary-30);
66
+ /* F-023 Decision 2: was var(--dda-primary-30) — 4.05:1 against the alert's
67
+ info text, failing 4.5:1. Darkening the fill (not the text, which is
68
+ also the alert's border/link/icon colour) brings it to 5.72:1. */
69
+ --dda-primary-variant-95: var(--dda-primary-20);
67
70
  --dda-primary-variant-94: var(--dda-primary-25);
68
71
  --dda-primary-variant-92: var(--dda-primary-20);
69
72
  --dda-primary-variant-87: var(--dda-primary-12);
@@ -282,7 +285,11 @@
282
285
  }
283
286
  :root[data-theme='dark'] {
284
287
  --dda-color-warning-50: var(--dda-warning-80);
285
- --dda-color-warning-40: var(--dda-warning-50);
288
+ /* F-023 Decision 2: was var(--dda-warning-50) — 2.08:1 against the alert's
289
+ warning fill, failing both the 24px title's 3:1 and the description's
290
+ 4.5:1. This token is also the alert's border/link/icon colour, so the
291
+ text tone moves (not the fill) to stay in one place: 5.47:1. */
292
+ --dda-color-warning-40: var(--dda-warning-80);
286
293
  --dda-color-warning-30: var(--dda-warning-90);
287
294
  --dda-color-warning-20: var(--dda-warning-94);
288
295
 
@@ -499,6 +506,11 @@
499
506
  --dda-on-surface-30: var(--dda-neutral-30);
500
507
  --dda-on-surface-40: var(--dda-neutral-40);
501
508
  --dda-on-surface-0: var(--dda-neutral-0);
509
+
510
+ /* F-023 Decision 1: theme-aware muted/disabled-text alias. --dda-neutral-60
511
+ itself stays a theme-invariant raw ramp step; this alias is the
512
+ theme-aware layer for the 8 call sites that use it as text. */
513
+ --dda-on-surface-muted: var(--dda-neutral-40);
502
514
  }
503
515
 
504
516
  :root[data-theme='dark'] {
@@ -515,6 +527,8 @@
515
527
  --dda-on-surface-20: var(--dda-neutral-90);
516
528
  --dda-on-surface-30: var(--dda-neutral-80);
517
529
  --dda-on-surface-40: var(--dda-neutral-70);
530
+
531
+ --dda-on-surface-muted: var(--dda-neutral-70);
518
532
  }
519
533
 
520
534
  :root {
@@ -2036,6 +2050,16 @@
2036
2050
  width: 100%;
2037
2051
  z-index: 5;
2038
2052
  padding: 0 20px;
2053
+ transform: translateY(0);
2054
+ transition: transform 300ms ease-in-out;
2055
+ }
2056
+
2057
+ /* dda-sticky-footer toggles this class off its own scroll-direction state
2058
+ (see dda-sticky-footer.tsx handleScroll) to hide the bar while scrolling
2059
+ down and bring it back while scrolling up. Same transition idiom as
2060
+ .dda-header in dda-header-main.css. */
2061
+ .dda-footer.hidden {
2062
+ transform: translateY(100%);
2039
2063
  }
2040
2064
 
2041
2065
  .footer-content {
@@ -210,7 +210,6 @@
210
210
  cursor: pointer;
211
211
  }
212
212
 
213
- .dda-input-dropdown-item:focus-visible,
214
213
  .dda-input-dropdown-item:hover {
215
214
  background-color: var(--dda-neutral-variant-95);
216
215
  outline: 0;
@@ -295,14 +294,14 @@
295
294
  .dda-input-disabled .dda-dropdown-select,
296
295
  .dda-input-disabled .dda-file-input span,
297
296
  .dda-input-disabled .dda-file-choose {
298
- color: var(--dda-neutral-60) !important;
297
+ color: var(--dda-on-surface-muted) !important;
299
298
  }
300
299
 
301
300
  .dda-input-disabled .dda-input-field-group,
302
301
  .dda-input-disabled .dda-input-field {
303
- background: var(--dda-neutral-92);
302
+ background: var(--dda-surface-92);
304
303
  border-color: var(--dda-neutral-90);
305
- color: var(--dda-neutral-60) !important;
304
+ color: var(--dda-on-surface-muted) !important;
306
305
  box-shadow: none;
307
306
  pointer-events: none;
308
307
  }
@@ -313,11 +312,11 @@
313
312
  fill: var(--dda-neutral-variant-60);
314
313
  }
315
314
  .dda-input-disabled .dda-input-field::-ms-input-placeholder {
316
- color: var(--dda-neutral-60);
315
+ color: var(--dda-on-surface-muted);
317
316
  }
318
317
 
319
318
  .dda-input-disabled .dda-input-field::placeholder {
320
- color: var(--dda-neutral-60);
319
+ color: var(--dda-on-surface-muted);
321
320
  }
322
321
 
323
322
  .dda-input-disabled .dda-btn {
@@ -552,7 +551,7 @@
552
551
  }
553
552
  .dda-file-choose {
554
553
  height: 40px;
555
- background-color: var(--dda-neutral-100);
554
+ background-color: var(--dda-surface-100);
556
555
  border: solid 1px var(--dda-neutral-90);
557
556
  color: var(--dda-color-primary-40);
558
557
  font-weight: var(--dda-fw-500);
@@ -566,7 +565,7 @@
566
565
  }
567
566
 
568
567
  .dda-input-disabled .dda-file-choose {
569
- background-color: var(--dda-neutral-95);
568
+ background-color: var(--dda-surface-94);
570
569
  }
571
570
 
572
571
  .dda-file-choose input {
@@ -613,3 +612,65 @@
613
612
  padding: 0px;
614
613
  }
615
614
 
615
+ /**
616
+ * WCAG 2.4.7/1.4.11 focus-visible repair (Task 9d: F-021).
617
+ *
618
+ * `.dda-validation-error .dda-input-field` and `.dda-input-disabled
619
+ * .dda-input-field` (above) both set `box-shadow: none` unconditionally,
620
+ * regardless of focus state, at the same or higher specificity than the
621
+ * base `.dda-input-field:focus` ring (line ~78) - so on these two states
622
+ * the ring never rendered at all. Neither state's story sets the real
623
+ * `disabled` attribute on the underlying <input>/<textarea>/<button>, so
624
+ * these remain real, reachable Tab stops. `.dda-dropdown-container.bg-
625
+ * transparent .dda-dropdown-header` has the same defect by a different
626
+ * route: `box-shadow: none` at *higher* specificity than the base ring it
627
+ * shares via its own `dda-input-field` class. `.ql-editor` (Quill's rich-
628
+ * text region, dda-textarea's enable_rich_editor mode) never had a focus
629
+ * rule of any kind - it carries no dda-* class at all.
630
+ *
631
+ * `.dda-input-dropdown-item:focus-visible` (Task: final-fix-wave, F-002's
632
+ * arrow-navigable dda-select option list): was paired with `:hover` at
633
+ * line ~213, `outline: 0`, background-only - 1.13:1 against the list
634
+ * background, identical to the `:hover` state, so a keyboard user could
635
+ * not tell focus from a stray pointer. Split from `:hover` and given the
636
+ * same double-ring here instead. Shared by dda-select, dda-avatar,
637
+ * dda-phonefield and dda-number-field's option lists, all of which use
638
+ * this one class.
639
+ *
640
+ * Each fix below adds `:focus-visible` to the exact selector that broke
641
+ * the ring, which raises its specificity strictly above the offending rule
642
+ * (or, for the validation-error case, ties the `.light-mode` variant's
643
+ * specificity - placed at the end of the file so source order also
644
+ * resolves in its favour). Same white+dark double-ring idiom as
645
+ * `.dda-btn:focus-visible` (dda-button.css) and dda-home-banner's
646
+ * `.slider-nav *:focus-visible` (home-banner.css:182-187) - one focus-ring
647
+ * recipe reused everywhere. Fixed white/black colours need no per-theme or
648
+ * per-`.light-mode` variant: for any background, at least one of pure
649
+ * white or pure black clears 3:1 against it - verified against every
650
+ * background this task touched (input/textarea/select/search-input/
651
+ * creditcard-field's surface-100 and disabled-neutral-92 backgrounds, the
652
+ * rich editor's white background, and the dropdown's transparent-over-
653
+ * surface-100 background) in both `data-theme` values; see the task 9d
654
+ * report for the computed ratios.
655
+ */
656
+ .dda-validation-error .dda-input-field:focus-visible,
657
+ .dda-input-disabled .dda-input-field:focus-visible {
658
+ outline: none;
659
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(0, 0, 0, 0.65);
660
+ }
661
+
662
+ .dda-dropdown-container.bg-transparent .dda-dropdown-header:focus-visible {
663
+ outline: none;
664
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(0, 0, 0, 0.65);
665
+ }
666
+
667
+ .dda-richeditor-field .ql-editor:focus-visible {
668
+ outline: none;
669
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(0, 0, 0, 0.65);
670
+ }
671
+
672
+ .dda-input-dropdown-item:focus-visible {
673
+ outline: none;
674
+ box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(0, 0, 0, 0.65);
675
+ }
676
+
@@ -0,0 +1,38 @@
1
+ // F-023: shared test helper for asserting the *contrast outcome* of a
2
+ // foreground/background pairing, not the CSS custom property name behind it.
3
+ // Not consumed by any component — used only from e2e specs, which read real
4
+ // `getComputedStyle()` color strings (e.g. "rgb(94, 96, 95)") from a
5
+ // rendered page and pass them here.
6
+ /**
7
+ * Parses a CSS color string as returned by `getComputedStyle()`
8
+ * (`rgb(r, g, b)` or `rgba(r, g, b, a)`) into its channel values.
9
+ */
10
+ export function parseRgb(color) {
11
+ const match = color.match(/rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)/i);
12
+ if (!match) {
13
+ throw new Error(`contrast.ts: could not parse computed color "${color}"`);
14
+ }
15
+ return { r: Number(match[1]), g: Number(match[2]), b: Number(match[3]) };
16
+ }
17
+ function channelLuminance(channel) {
18
+ const c = channel / 255;
19
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
20
+ }
21
+ /** WCAG relative luminance, 0 (black) to 1 (white). */
22
+ export function relativeLuminance({ r, g, b }) {
23
+ return 0.2126 * channelLuminance(r) + 0.7152 * channelLuminance(g) + 0.0722 * channelLuminance(b);
24
+ }
25
+ /**
26
+ * WCAG contrast ratio between two colors, each either a `getComputedStyle()`
27
+ * color string or a pre-parsed { r, g, b }. Order doesn't matter — the
28
+ * lighter color is always treated as the numerator, per spec.
29
+ */
30
+ export function contrastRatio(a, b) {
31
+ const rgbA = typeof a === 'string' ? parseRgb(a) : a;
32
+ const rgbB = typeof b === 'string' ? parseRgb(b) : b;
33
+ const lumA = relativeLuminance(rgbA);
34
+ const lumB = relativeLuminance(rgbB);
35
+ const lighter = Math.max(lumA, lumB);
36
+ const darker = Math.min(lumA, lumB);
37
+ return (lighter + 0.05) / (darker + 0.05);
38
+ }